import { Injectable, inject } from '@angular/core';
import { Apollo } from 'apollo-angular';
import { map, Observable } from 'rxjs';
import {
  Student, StudentPayload, DeletePayload,
  CreateStudentInput, UpdateStudentInput
} from '@core/models';
import { GET_STUDENTS, GET_STUDENT } from '@core/graphql/queries/students.queries';
import { CREATE_STUDENT, UPDATE_STUDENT, DELETE_STUDENT } from '@core/graphql/mutations/students.mutations';

interface StudentsQueryResult {
  students: Student[];
}

interface StudentQueryResult {
  student: Student | null;
}

interface CreateStudentResult {
  createStudent: StudentPayload;
}

interface UpdateStudentResult {
  updateStudent: StudentPayload;
}

interface DeleteStudentResult {
  deleteStudent: DeletePayload;
}

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

  getStudents(): Observable<{ data: Student[]; loading: boolean }> {
    return this.apollo
      .watchQuery<StudentsQueryResult>({
        query: GET_STUDENTS,
        fetchPolicy: 'cache-and-network',
      })
      .valueChanges.pipe(
        map(result => ({
          data: (result.data?.students ?? []) as Student[],
          loading: result.loading,
        }))
      );
  }

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

  createStudent(input: CreateStudentInput): Observable<StudentPayload> {
    return this.apollo
      .mutate<CreateStudentResult>({
        mutation: CREATE_STUDENT,
        variables: { input },
        refetchQueries: [{ query: GET_STUDENTS }],
      })
      .pipe(map(result => result.data?.createStudent ?? {}));
  }

  updateStudent(id: number, input: UpdateStudentInput): Observable<StudentPayload> {
    return this.apollo
      .mutate<UpdateStudentResult>({
        mutation: UPDATE_STUDENT,
        variables: { id, input },
        refetchQueries: [{ query: GET_STUDENTS }],
      })
      .pipe(map(result => result.data?.updateStudent ?? {}));
  }

  deleteStudent(id: number): Observable<DeletePayload> {
    return this.apollo
      .mutate<DeleteStudentResult>({
        mutation: DELETE_STUDENT,
        variables: { id },
        refetchQueries: [{ query: GET_STUDENTS }],
      })
      .pipe(map(result => result.data?.deleteStudent ?? { success: false }));
  }
}
