import { create } from 'zustand';
import api from './api';

/**
 * ClassDetail store — Phase 1 PR 3 (2026-07-22).
 *
 * Holds the per-class detail payload (subjects + students + teachers +
 * active covers + cohorts) and exposes the write actions for the
 * ClassDetail tabs: change form tutor, change subject teacher, bulk
 * enrol, transfer student, withdraw student.
 *
 * The page itself owns the tab UI; this store is the single source of
 * truth for the data so the tabs stay in sync without a parent-prop
 * cascade.
 */

export interface ClassSubject {
  id: number;
  uid: string;
  name: string;
  code: string | null;
  class_id: number;
  teacher_id: number | null;
  teacher_name: string | null;
  teacher_email: string | null;
  description: string | null;
}

export interface ClassStudent {
  id: number;
  uid: string;
  first_name: string;
  last_name: string;
  email: string;
  phone: string | null;
  roll_number: string | null;
  enrollment_id: number;
  enrollment_status: 'active' | 'inactive' | 'transferred' | 'graduated';
  request_status: 'pending' | 'approved' | 'rejected' | 'withdrawn';
}

export interface ClassTeacherSummary {
  id: number;
  name: string;
  email: string;
}

export interface ActiveCover {
  id: number;
  user_id: number;
  role: string;
  starts_at: string | null;
  expires_at: string | null;
  reason: string | null;
  user_name: string;
  user_email: string;
}

export interface ClassCohortSummary {
  id: number;
  name: string;
  programme: string;
  level: string | null;
  academic_year: string | null;
}

export interface ClassDetailData {
  id: number;
  uid: string;
  name: string;
  section: string | null;
  capacity: number | null;
  description: string | null;
  class_teacher_id: number | null;
  class_teacher_name: string | null;
  class_teacher_email: string | null;
  subjects: ClassSubject[];
  students: ClassStudent[];
  teachers: {
    class_teacher: ClassTeacherSummary | null;
    subject_teachers: (ClassSubject & {
      subject_id: number;
      subject_name: string;
      subject_code: string | null;
    })[];
    active_covers: ActiveCover[];
  };
  cohorts: ClassCohortSummary[];
  fetched_at: string;
}

interface ClassDetailState {
  detailById: Record<number, ClassDetailData | null>;
  loading: boolean;
  error: string | null;
  fetchDetail: (id: number) => Promise<ClassDetailData>;
  setFormTeacher: (classId: number, teacherId: number | null) => Promise<void>;
  setSubjectTeacher: (
    classId: number,
    subjectId: number,
    teacherId: number | null
  ) => Promise<void>;
  bulkEnrol: (classId: number, studentIds: number[]) => Promise<{ added: number[]; skipped: number[]; errors: any[] }>;
  transferStudent: (enrollmentId: number, newClassId: number, reason?: string) => Promise<void>;
  withdrawStudent: (enrollmentId: number) => Promise<void>;
  invalidate: (id: number) => void;
}

export const useClassDetailStore = create<ClassDetailState>((set, get) => ({
  detailById: {},
  loading: false,
  error: null,

  fetchDetail: async (id) => {
    set({ loading: true, error: null });
    try {
      // Compose the detail from the four endpoints that already exist.
      // The backend doesn't have a single /api/classes/:id/detail that
      // returns everything; the page calls each one and we surface the
      // union here.
      const [cls, teachers, enrollments, cohorts] = await Promise.all([
        api.get(`/classes/${id}`),
        api.get(`/classes/${id}/teachers`).catch(() => ({ data: { class_teacher: null, subject_teachers: [], active_covers: [] } })),
        api.get(`/enrollments`, { params: { class_id: id, status: 'active' } }).catch(() => ({ data: [] })),
        api.get(`/cohorts`).then((r) => {
          const all = r.data?.cohorts || [];
          return { data: { cohorts: all.filter((c: any) => Array.isArray(c.classes) && c.classes.some((cl: any) => cl.id === id)) } };
        }).catch(() => ({ data: { cohorts: [] } })),
      ]);

      const clsData = cls.data;
      const subjects = clsData.subjects || [];
      const studentsRaw: any[] = (clsData.students || []);
      const enrolmentMap = new Map<number, any>((enrollments.data || []).map((e: any) => [e.student_id, e]));
      const students: ClassStudent[] = studentsRaw.map((s) => {
        const enrol = enrolmentMap.get(s.id) || {};
        return {
          id: s.id,
          uid: s.uid,
          first_name: s.first_name,
          last_name: s.last_name,
          email: s.email,
          phone: s.phone || null,
          roll_number: s.roll_number || null,
          enrollment_id: enrol.id,
          enrollment_status: enrol.status || 'active',
          request_status: enrol.request_status || 'approved',
        };
      });

      const detail: ClassDetailData = {
        id: clsData.id,
        uid: clsData.uid,
        name: clsData.name,
        section: clsData.section,
        capacity: clsData.capacity,
        description: clsData.description,
        class_teacher_id: clsData.class_teacher_id,
        class_teacher_name: clsData.class_teacher_name || null,
        class_teacher_email: null,
        subjects,
        students,
        teachers: teachers.data,
        cohorts: cohorts.data?.cohorts || [],
        fetched_at: new Date().toISOString(),
      };
      set((s) => ({
        detailById: { ...s.detailById, [id]: detail },
        loading: false,
      }));
      return detail;
    } catch (err: any) {
      const msg = err.response?.data?.error || err.message || 'Failed to load class';
      set({ loading: false, error: msg });
      throw new Error(msg);
    }
  },

  setFormTeacher: async (classId, teacherId) => {
    try {
      const { data } = await api.put(`/classes/${classId}/class-teacher`, { teacherId });
      set((s) => {
        const cur = s.detailById[classId];
        if (!cur) return s;
        return {
          detailById: {
            ...s.detailById,
            [classId]: {
              ...cur,
              class_teacher_id: data.class_teacher_id,
              class_teacher_name: data.class_teacher_name,
              teachers: {
                ...cur.teachers,
                class_teacher: data.class_teacher_id
                  ? { id: data.class_teacher_id, name: data.class_teacher_name, email: cur.teachers.class_teacher?.email || '' }
                  : null,
              },
            },
          },
        };
      });
    } catch (err: any) {
      const msg = err.response?.data?.error || err.message || 'Failed to update form tutor';
      set({ error: msg });
      throw new Error(msg);
    }
  },

  setSubjectTeacher: async (classId, subjectId, teacherId) => {
    try {
      const { data } = await api.post(`/classes/${classId}/subjects/${subjectId}/teacher`, { teacherId });
      set((s) => {
        const cur = s.detailById[classId];
        if (!cur) return s;
        return {
          detailById: {
            ...s.detailById,
            [classId]: {
              ...cur,
              subjects: cur.subjects.map((sub) => (sub.id === subjectId ? { ...sub, teacher_id: data.teacher_id, teacher_name: data.teacher_name } : sub)),
              teachers: {
                ...cur.teachers,
                subject_teachers: cur.teachers.subject_teachers.map((st) =>
                  st.subject_id === subjectId
                    ? { ...st, teacher_id: data.teacher_id, teacher_name: data.teacher_name, teacher_email: data.teacher_email }
                    : st
                ),
              },
            },
          },
        };
      });
    } catch (err: any) {
      const msg = err.response?.data?.error || err.message || 'Failed to update subject teacher';
      set({ error: msg });
      throw new Error(msg);
    }
  },

  bulkEnrol: async (classId, studentIds) => {
    try {
      const { data } = await api.post(`/students/bulk-enroll`, {
        classId,
        studentIds,
      });
      // Re-fetch to refresh the roster
      await get().fetchDetail(classId);
      return data;
    } catch (err: any) {
      const msg = err.response?.data?.error || err.message || 'Bulk enrol failed';
      set({ error: msg });
      throw new Error(msg);
    }
  },

  transferStudent: async (enrollmentId, newClassId, reason) => {
    try {
      await api.post(`/enrollments/${enrollmentId}/transfer`, { newClassId, reason });
    } catch (err: any) {
      const msg = err.response?.data?.error || err.message || 'Transfer failed';
      set({ error: msg });
      throw new Error(msg);
    }
  },

  withdrawStudent: async (enrollmentId) => {
    try {
      await api.post(`/enrollments/${enrollmentId}/withdraw`, {});
    } catch (err: any) {
      const msg = err.response?.data?.error || err.message || 'Withdraw failed';
      set({ error: msg });
      throw new Error(msg);
    }
  },

  invalidate: (id) => {
    set((s) => {
      const next = { ...s.detailById };
      delete next[id];
      return { detailById: next };
    });
  },
}));
