import { Injectable, inject } from '@angular/core';
import { Apollo } from 'apollo-angular';
import { map, Observable } from 'rxjs';
import {
  AvailableSubject, Classmate, EnrollmentPayload, DeletePayload, EnrollInput, Student
} from '@core/models';
import { GET_AVAILABLE_SUBJECTS, GET_CLASSMATES, GET_STUDENT } from '@core/graphql/queries/students.queries';
import { ENROLL_STUDENT, UNENROLL_STUDENT } from '@core/graphql/mutations/students.mutations';

interface AvailableSubjectsResult {
  availableSubjects: AvailableSubject[];
}

interface ClassmatesResult {
  classmates: Classmate[];
}

interface StudentResult {
  student: Student | null;
}

interface EnrollResult {
  enrollStudent: EnrollmentPayload;
}

interface UnenrollResult {
  unenrollStudent: DeletePayload;
}

@Injectable({ providedIn: 'root' })
export class EnrollmentService {
  private apollo = inject(Apollo);

  getStudentWithEnrollments(studentId: number): Observable<{ data: Student | null; loading: boolean }> {
    return this.apollo
      .watchQuery<StudentResult>({
        query: GET_STUDENT,
        variables: { id: studentId },
        fetchPolicy: 'cache-and-network',
      })
      .valueChanges.pipe(
        map(result => ({
          data: (result.data?.student ?? null) as Student | null,
          loading: result.loading,
        }))
      );
  }

  getAvailableSubjects(studentId: number): Observable<{ data: AvailableSubject[]; loading: boolean }> {
    return this.apollo
      .watchQuery<AvailableSubjectsResult>({
        query: GET_AVAILABLE_SUBJECTS,
        variables: { studentId },
        fetchPolicy: 'network-only',
      })
      .valueChanges.pipe(
        map(result => ({
          data: (result.data?.availableSubjects ?? []) as AvailableSubject[],
          loading: result.loading,
        }))
      );
  }

  getClassmates(studentId: number): Observable<{ data: Classmate[]; loading: boolean }> {
    return this.apollo
      .watchQuery<ClassmatesResult>({
        query: GET_CLASSMATES,
        variables: { studentId },
        fetchPolicy: 'cache-and-network',
      })
      .valueChanges.pipe(
        map(result => ({
          data: (result.data?.classmates ?? []) as Classmate[],
          loading: result.loading,
        }))
      );
  }

  enrollStudent(input: EnrollInput): Observable<EnrollmentPayload> {
    return this.apollo
      .mutate<EnrollResult>({
        mutation: ENROLL_STUDENT,
        variables: { input },
        refetchQueries: [
          { query: GET_STUDENT, variables: { id: input.studentId } },
          { query: GET_AVAILABLE_SUBJECTS, variables: { studentId: input.studentId } },
        ],
      })
      .pipe(map(result => result.data?.enrollStudent ?? {}));
  }

  unenrollStudent(enrollmentId: number, studentId: number): Observable<DeletePayload> {
    return this.apollo
      .mutate<UnenrollResult>({
        mutation: UNENROLL_STUDENT,
        variables: { enrollmentId },
        refetchQueries: [
          { query: GET_STUDENT, variables: { id: studentId } },
          { query: GET_AVAILABLE_SUBJECTS, variables: { studentId } },
        ],
      })
      .pipe(map(result => result.data?.unenrollStudent ?? { success: false }));
  }
}
