/**
 * Reports store (Phase 2 analytics dashboard).
 *
 * Wraps the new /api/reports/{kpis, timeseries, cohorts, export} endpoints.
 * Role-scoped data is filtered server-side; the store just normalizes the
 * shape and surfaces loading/error states.
 *
 * Pattern follows the canonical exams.ts reference: api (axios from ./api)
 * gets the JWT via its interceptor; the store only owns data + fetch
 * methods + reset.
 */

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

// ---------- Types ---------------------------------------------------------

export interface KpiEnrollments {
  total: number;
  active: number;
  newThisTerm: number;
  byProgramme: Record<string, number>;
}

export interface KpiAttendance {
  rate30d: number;
  rate7d: number;
  trend: 'up' | 'down' | 'flat';
}

export interface KpiAcademics {
  avgMark: number;
  passRate: number;
  topSubject: string | null;
  bottomSubject: string | null;
}

export interface KpiFinance {
  collected30d: number;
  outstanding: number;
  overdueCount: number;
}

export interface KpiStaff {
  activeTeachers: number;
  onLeave: number;
  pendingApprovals: number;
}

export interface KpiPayload {
  enrollments: KpiEnrollments;
  attendance: KpiAttendance;
  academics: KpiAcademics;
  // Optional, role-gated server-side:
  finance?: KpiFinance;
  staff?: KpiStaff;
}

export interface TimeseriesPoint {
  month: string;
  yearMonth: string;
  students?: number;
  teachers?: number;
  revenue?: number;
  expenses?: number;
  net?: number;
}

export interface CohortRow {
  id: number;
  cohort_id?: number;
  name: string;
  code?: string | null;
  programme?: string;
  academic_year?: string;
  student_count: number;
  pass_rate?: number;
  avg_pct?: number;
  avg_marks?: number;
}

export interface CohortsPayload {
  source: 'cohorts' | 'classes_fallback' | 'none';
  data: CohortRow[];
}

// ---------- Store ---------------------------------------------------------

interface ReportsState {
  // Data
  kpis: KpiPayload | null;
  timeseries: { range: string; series: TimeseriesPoint[] };
  cohorts: CohortsPayload;
  // Per-tab aux data (still served by existing endpoints)
  academic: { subjects: any[]; classes: any[] };
  financial: any | null;
  hr: any | null;
  summary: any | null;

  // Filters (driven from the FilterBar component)
  range: string;

  // Status
  loading: boolean;
  error: string | null;

  // Actions
  setRange: (r: string) => void;
  loadAll: () => Promise<void>;
  loadKpis: () => Promise<void>;
  loadTimeseries: () => Promise<void>;
  loadCohorts: () => Promise<void>;
  reset: () => void;
}

export const useReportsStore = create<ReportsState>((set, get) => ({
  kpis: null,
  timeseries: { range: '6m', series: [] },
  cohorts: { source: 'none', data: [] },
  academic: { subjects: [], classes: [] },
  financial: null,
  hr: null,
  summary: null,
  range: '6m',
  loading: false,
  error: null,

  setRange: (range) => set({ range }),

  loadKpis: async () => {
    try {
      const r = await api.get('/reports/kpis');
      set({ kpis: r.data });
    } catch (e: any) {
      // kpis is allowed to fail (e.g. on /api/health-style probes); do not surface.
      console.warn('[reports] loadKpis failed', e?.message);
    }
  },

  loadTimeseries: async () => {
    const { range } = get();
    try {
      const r = await api.get('/reports/timeseries', { params: { range } });
      set({ timeseries: r.data });
    } catch (e: any) {
      console.warn('[reports] loadTimeseries failed', e?.message);
    }
  },

  loadCohorts: async () => {
    try {
      const r = await api.get('/reports/cohorts');
      set({ cohorts: r.data });
    } catch (e: any) {
      console.warn('[reports] loadCohorts failed', e?.message);
    }
  },

  loadAll: async () => {
    set({ loading: true, error: null });
    try {
      const [summaryRes, kpiRes, tsRes, acadRes, finRes, hrRes, cohortsRes] = await Promise.allSettled([
        api.get('/reports/summary', { params: { range: get().range } }),
        api.get('/reports/kpis'),
        api.get('/reports/timeseries', { params: { range: get().range } }),
        api.get('/reports/academic'),
        api.get('/reports/financial'),
        api.get('/reports/hr'),
        api.get('/reports/cohorts'),
      ]);

      set({
        summary: summaryRes.status === 'fulfilled' ? summaryRes.value.data : null,
        kpis: kpiRes.status === 'fulfilled' ? kpiRes.value.data : null,
        timeseries: tsRes.status === 'fulfilled' ? tsRes.value.data : { range: get().range, series: [] },
        academic: acadRes.status === 'fulfilled' ? acadRes.value.data : { subjects: [], classes: [] },
        financial: finRes.status === 'fulfilled' ? finRes.value.data : null,
        hr: hrRes.status === 'fulfilled' ? hrRes.value.data : null,
        cohorts: cohortsRes.status === 'fulfilled' ? cohortsRes.value.data : { source: 'none', data: [] },
      });
    } catch (e: any) {
      set({ error: e?.message ?? 'Failed to load reports' });
    } finally {
      set({ loading: false });
    }
  },

  reset: () =>
    set({
      kpis: null,
      timeseries: { range: '6m', series: [] },
      cohorts: { source: 'none', data: [] },
      academic: { subjects: [], classes: [] },
      financial: null,
      hr: null,
      summary: null,
      range: '6m',
      loading: false,
      error: null,
    }),
}));

/**
 * Trigger a CSV download for the given export type. Uses the new
 * /api/reports/export?type=...&format=csv streaming endpoint.
 */
export async function downloadCsv(
  type: 'overview' | 'academics' | 'cohorts' | 'finance',
  params: { range?: string; cohort?: string } = {},
): Promise<void> {
  const r = await api.get('/reports/export', {
    params: { type, format: 'csv', ...params },
    responseType: 'blob',
  });
  const blob = new Blob([r.data], { type: 'text/csv;charset=utf-8' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  const ts = new Date().toISOString().replace(/[:.]/g, '-');
  a.href = url;
  a.download = `${type}_export_${ts}.csv`;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  setTimeout(() => URL.revokeObjectURL(url), 1000);
}