/**
 * Attendance Module - Zustand Store
 *
 * Unified store for the four attendance contexts added by the
 * 2026-06-12 backend change:
 *
 *   - 'class'     → /api/attendance            (existing controller)
 *   - 'hostel'    → /api/hostel-attendance     (new)
 *   - 'transport' → /api/transport-attendance  (new)
 *   - 'club'      → /api/club-attendance       (new — use the new URL, not
 *                                                 the legacy /api/clubs/attendance)
 *
 * The store routes the calls to the right controller based on `context`
 * so the page code never has to know which endpoint family it's talking to.
 *
 * Endpoint shape (per backend deliverable 2026-06-12):
 *
 *   GET    /{context}-attendance              list, supports date / from / to
 *                                              plus the scoping param
 *                                              (class_id | hostel_id+room_id
 *                                               | route_id | club_id)
 *   GET    /{context}-attendance/roster       expected students for a date
 *   POST   /{context}-attendance/bulk         body: { date, records: [...], scoping-key }
 *   GET    /{context}-attendance/history      per-student history
 *
 *   For 'class' the URL is /attendance (no 'class-' prefix).
 *   The roster + bulk endpoints for the class context reuse the existing
 *   /attendance and /attendance/bulk routes — see
 *   server/src/controllers/attendance.controller.js.
 */

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

export type AttendanceContext = 'class' | 'hostel' | 'transport' | 'club' | 'staff';
export type AttendanceStatus = 'present' | 'absent' | 'excused';

/* ---------- roster row (returned by /roster) ---------- */

export interface RosterRow {
  // the column names differ slightly across contexts but all are
  // mapped to the same shape on the page side
  student_id: number;
  student_name: string;
  status: AttendanceStatus | null; // null = not yet marked
  attendance_id: number | null;
  date?: string;

  // context-specific extras kept loose
  [key: string]: any;
}

export interface RosterResponse {
  date: string;
  total: number;
  roster: RosterRow[];
  // 'class' /roster returns the rows directly (no wrapper) — caller
  // handles the difference via the unwrapRoster helper below.
  [key: string]: any;
}

/* ---------- history record (returned by /history) ---------- */

export interface AttendanceRecord {
  id: number;
  date: string;
  status: AttendanceStatus;
  // context-specific joined columns
  [key: string]: any;
}

export interface AttendanceSummary {
  total: number;
  present: number;
  absent: number;
  excused: number;
}

export interface HistoryResponse {
  student_id: number;
  summary: AttendanceSummary;
  records: AttendanceRecord[];
}

/* ---------- bulk submit shape ---------- */

export interface BulkRecord {
  student_id: number;
  status: AttendanceStatus;
  remarks?: string;
}

export interface BulkResult {
  success: boolean;
  inserted: number;
  updated: number;
  total: number;
}

/* ---------- URL helpers ---------- */

const baseFor = (ctx: AttendanceContext): string => {
  if (ctx === 'class') return '/attendance';
  return `/${ctx}-attendance`;
};

/**
 * The 'class' /roster endpoint isn't shipped by the backend
 * (we just GET /attendance?class_id=&date= and build the roster client-side
 * from enrolled students), so we treat it as a "no-op" for class and let
 * the page load students + existing attendance separately. For the other
 * contexts the backend returns a proper { date, total, roster }.
 */
const unwrapRoster = (ctx: AttendanceContext, payload: any): RosterResponse => {
  if (ctx === 'class') {
    // No dedicated /roster for class — return an empty roster and let the
    // page use /classes/{id}/students or /enrollments instead.
    return { date: payload?.date || '', total: 0, roster: [] };
  }
  if (Array.isArray(payload)) {
    return { date: '', total: payload.length, roster: payload as RosterRow[] };
  }
  return {
    date: payload?.date || '',
    total: payload?.total ?? payload?.roster?.length ?? 0,
    roster: (payload?.roster || []) as RosterRow[],
  };
};

/* ---------- store interface ---------- */

interface AttendanceStore {
  // state — separate slots per context to avoid stomping
  classRoster: RosterRow[];
  hostelRoster: RosterRow[];
  transportRoster: RosterRow[];
  clubRoster: RosterRow[];
  staffRoster: RosterRow[];

  history: AttendanceRecord[];
  historySummary: AttendanceSummary | null;
  historyStudentId: number | null;
  historyContext: AttendanceContext | null;

  lastBulkResult: BulkResult | null;
  loading: boolean;
  error: string | null;

  // roster
  fetchRoster: (
    context: AttendanceContext,
    params: { date?: string; class_id?: number; hostel_id?: number; room_id?: number; route_id?: number; club_id?: number; role?: string }
  ) => Promise<RosterResponse>;

  // bulk submit
  submitBulkAttendance: (
    context: AttendanceContext,
    payload: {
      date: string;
      class_id?: number;
      hostel_id?: number;
      room_id?: number;
      route_id?: number;
      club_id?: number;
      records: BulkRecord[];
    }
  ) => Promise<BulkResult>;

  // history
  fetchHistory: (
    context: AttendanceContext,
    studentId: number,
    dateRange?: { from?: string; to?: string }
  ) => Promise<HistoryResponse>;

  // list (just the raw rows — mostly used by history pages for richer views)
  fetchList: (
    context: AttendanceContext,
    params: { date?: string; from?: string; to?: string; class_id?: number; hostel_id?: number; route_id?: number; club_id?: number; student_id?: number }
  ) => Promise<AttendanceRecord[]>;
}

/* ---------- implementation ---------- */

export const useAttendanceStore = create<AttendanceStore>((set, get) => ({
  classRoster: [],
  hostelRoster: [],
  transportRoster: [],
  clubRoster: [],
  staffRoster: [],

  history: [],
  historySummary: null,
  historyStudentId: null,
  historyContext: null,

  lastBulkResult: null,
  loading: false,
  error: null,

  // ============ ROSTER ============

  fetchRoster: async (context, params) => {
    set({ loading: true, error: null });
    try {
      const base = baseFor(context);
      if (context === 'class') {
        // No /roster endpoint for class — return empty and let the page
        // derive the roster from /classes/{id}/students or /enrollments.
        const empty: RosterResponse = { date: params.date || '', total: 0, roster: [] };
        set({ classRoster: [], loading: false });
        return empty;
      }
      const res = await api.get(`${base}/roster`, { params });
      const unwrapped = unwrapRoster(context, res.data);
      set(state => {
        const patch: Partial<AttendanceStore> = { loading: false };
        if (context === 'hostel') patch.hostelRoster = unwrapped.roster;
        if (context === 'transport') patch.transportRoster = unwrapped.roster;
        if (context === 'club') patch.clubRoster = unwrapped.roster;
        if (context === 'staff') patch.staffRoster = unwrapped.roster;
        return patch as AttendanceStore;
      });
      return unwrapped;
    } catch (err: any) {
      set({ error: err?.message || `Failed to load ${context} roster`, loading: false });
      console.error('fetchRoster error', err);
      throw err;
    }
  },

  // ============ BULK SUBMIT ============

  submitBulkAttendance: async (context, payload) => {
    set({ loading: true, error: null });
    try {
      const base = baseFor(context);
      // /attendance (class) accepts the same { date, records, class_id }
      // shape; the other three use the new /bulk endpoint.
      const res = await api.post(`${base}/bulk`, payload);
      const result: BulkResult = {
        success: true,
        inserted: res.data?.inserted ?? 0,
        updated: res.data?.updated ?? 0,
        total: res.data?.total ?? payload.records.length,
      };
      set({ lastBulkResult: result, loading: false });
      return result;
    } catch (err: any) {
      const result: BulkResult = { success: false, inserted: 0, updated: 0, total: 0 };
      set({ error: err?.message || 'Failed to submit attendance', loading: false, lastBulkResult: result });
      console.error('submitBulkAttendance error', err);
      return result;
    }
  },

  // ============ HISTORY ============

  fetchHistory: async (context, studentId, dateRange) => {
    set({ loading: true, error: null });
    try {
      const base = baseFor(context);
      const params: Record<string, string> = { student_id: String(studentId) };
      if (dateRange?.from) params.from = dateRange.from;
      if (dateRange?.to) params.to = dateRange.to;
      const res = await api.get(`${base}/history`, { params });
      const payload = res.data as HistoryResponse;
      set({
        history: payload.records || [],
        historySummary: payload.summary || null,
        historyStudentId: studentId,
        historyContext: context,
        loading: false,
      });
      return payload;
    } catch (err: any) {
      set({ error: err?.message || 'Failed to load history', loading: false });
      console.error('fetchHistory error', err);
      throw err;
    }
  },

  // ============ LIST ============

  fetchList: async (context, params) => {
    set({ loading: true, error: null });
    try {
      const base = baseFor(context);
      const query: Record<string, string> = {};
      if (params.date) query.date = params.date;
      if (params.from) query.from = params.from;
      if (params.to) query.to = params.to;
      if (params.class_id) query.class_id = String(params.class_id);
      if (params.hostel_id) query.hostel_id = String(params.hostel_id);
      if (params.route_id) query.route_id = String(params.route_id);
      if (params.club_id) query.club_id = String(params.club_id);
      if (params.student_id) query.student_id = String(params.student_id);
      const res = await api.get(base, { params: query });
      set({ loading: false });
      return (res.data || []) as AttendanceRecord[];
    } catch (err: any) {
      set({ error: err?.message || `Failed to load ${context} list`, loading: false });
      console.error('fetchList error', err);
      return [];
    }
  },
}));

export default useAttendanceStore;
