/**
 * Dashboard store
 *
 * Role-specific dashboard data layer. Thin wrappers over GET /api/dashboard/<role>
 * that normalize response shapes into typed payloads and surface a 403 as an
 * explicit `accessDenied` flag so the page can render an "Access denied" state
 * rather than the role's normal layout when a student hits /api/dashboard/admin
 * (or any cross-role fetch).
 *
 * Pattern follows the canonical exams.ts reference: api (axios from ./api)
 * gets the JWT via its interceptor, the store only owns data + per-role fetch
 * methods + reset.
 */

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

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

export interface GradeDistribution {
  A: number;
  B: number;
  C: number;
  D: number;
  F: number;
  total: number;
}

export interface AdminDashboardData {
  // Legacy stat block (still returned by backend)
  stats?: {
    totalStudents: number;
    totalTeachers: number;
    totalClasses: number;
    totalRevenue: number;
    todayAttendance: { present: number; total: number };
    pendingFees: number;
  };
  // New role-aware analytics (added 2026-06-25, backend commit 89df1cd)
  active_enrollments: number;
  attendance_rate_30d: number;
  grade_distribution: GradeDistribution;
  programs_count: number;
  classes_count: number;
  users_by_role: Record<string, number>;
  // Other blocks the backend returns (kept optional so older payloads still typecheck)
  recentActivity?: unknown[];
  attendanceByDay?: unknown[];
  enrollmentByClass?: unknown[];
  // Shapeshift labels — see `dashboardLabels` server-side.
  labels?: TeacherDashboardLabels;
}

export interface PerCourseTeacher {
  course_id: number;
  course_name: string;
  avg_completion: number;
  median_score: number | null;
  students_below_threshold: number;
  enrolled: number;
}

export interface TeacherDashboardLabels {
  education_level: 'primary' | 'secondary' | 'high_school' | 'tertiary';
  marking: string;
  average: string;
  below_average: string;
  unit_singular: string;
  unit_plural: string;
}

export interface TeacherDashboardData {
  myClasses: { id: number; name: string; students: number }[];
  mySubjects: { id: number; name: string; code: string; className: string | null }[];
  todayStats: {
    totalStudents: number;
    periodsToday: number;
    studentsToMark: number;
    pendingTasks: number;
    unreadMessages: number;
    marking?: number;
    average?: number;
    belowAverage?: number;
  };
  recentMessages: Array<{
    id: number;
    subject: string;
    body: string;
    sender: string;
    sender_role?: string;
    time: string;
  }>;
  todaysAttendance: { marked: number; present: number; absent: number };
  per_course: PerCourseTeacher[];
  overall_students_count: number;
  pending_grading_count: number;
  marking?: number;
  average?: number;
  below_average?: number;
  // Education-level-aware KPI tile labels (shapeshift). Render these
  // on the dashboard tiles instead of hardcoding "Marking" / "Average"
  // / "Below Average".
  labels?: TeacherDashboardLabels;
}

export interface PerCourseStudent {
  course_id: number;
  course_name: string;
  average: number | null;
}

export interface RecentMark {
  id: number;
  subject: string;
  marks: number;
  total_marks: number;
  grade: string | null;
  exam_type: string | null;
  percent: number;
  graded_at: string;
}

export interface StudentDashboardData {
  // Legacy fields (still returned)
  attendancePercent: number;
  attendanceStats?: { present: number; absent: number; late: number; total: number };
  attendanceByDay?: Array<{ date: string; status: string; present: number }>;
  activeClasses: number;
  myClasses?: string[];
  mySubjects?: string[];
  feesSummary: { pending: number; paid: number };
  unreadMessages: number;
  pendingAssignments?: number;
  upcomingExams?: Array<{
    id: number;
    subject: string;
    className: string;
    startTime: string;
    durationMinutes: number;
    formattedDate: string;
    formattedTime: string;
  }>;
  recentGrades?: Array<{
    id: number;
    subject: string;
    marks: number;
    totalMarks: number;
    grade: string | null;
    examType: string | null;
    percent: number;
    time: string;
  }>;
  // New role-aware analytics
  per_course: PerCourseStudent[];
  pending_assignments_count: number;
  recent_marks: RecentMark[];
  gamification_points: number;
  leaderboard_rank: number | null;
  leaderboard_total_students: number;
  // Shapeshift labels (feature/shapeshift).
  labels?: TeacherDashboardLabels;
}

export interface AttendanceFlags {
  percent: number;
  total: number;
  present: number;
  absent: number;
  late: number;
  flag: 'low_attendance' | 'excessive_absences' | 'ok';
}

export interface FeeStatus {
  outstanding: number;
  paid_count: number;
  pending_count: number;
  total_count: number;
  flag: 'outstanding' | 'clear';
}

export interface GradeProgression {
  recent_avg_percent: number | null;
  prior_avg_percent: number | null;
  trend: number | null;
  direction: 'improving' | 'declining' | 'stable' | 'unknown';
}

export interface PerDependent {
  student_id: number;
  name: string;
  upcoming_deadlines: number;
  attendance_flags: AttendanceFlags;
  fee_status: FeeStatus;
  grade_progression: GradeProgression;
}

export interface ParentChild {
  id: number;
  first_name: string;
  last_name: string;
  full_name: string;
  email: string;
  gender: string | null;
  className: string | null;
  attendancePercent: number;
  averageGrade: number;
  letterGrade: string;
}

export interface ParentDashboardData {
  children: ParentChild[];
  childrenCount: number;
  feesSummary: { pending: number; paid: number; total: number };
  messages: Array<{
    id: number;
    subject: string;
    body: string;
    sender: string;
    sender_role?: string;
    priority?: string;
    isAnnouncement?: boolean;
    created_at: string;
  }>;
  upcomingEvents: Array<{
    id: number;
    title: string;
    description: string | null;
    date: string;
    type: string | null;
    venue: string | null;
    formattedDate: string;
  }>;
  per_dependent: PerDependent[];
  // Shapeshift labels (feature/shapeshift).
  labels?: TeacherDashboardLabels;
}

export type RoleDashboardData =
  | { role: 'admin'; data: AdminDashboardData }
  | { role: 'teacher'; data: TeacherDashboardData }
  | { role: 'student'; data: StudentDashboardData }
  | { role: 'parent'; data: ParentDashboardData };

// ---------- Phase 2 analytics payloads ---------------------------------

export interface InfrastructureHealth {
  db_size_bytes: number | null;
  db_size_mb: number | null;
  table_rows: Record<string, number | null>;
  sync_queue: { pending: number; synced: number };
  timestamp: string;
}

export interface SubjectGradeDistribution {
  subject_id: number;
  subject_name: string;
  distribution: { A: number; B: number; C: number; D: number; F: number };
  total: number;
  avg_pct: number;
}

export interface TeacherOutlier {
  student_id: number;
  student_name: string;
  course_id: number;
  course_name: string;
  avg_score: number;
  grades_count: number;
}

export interface TeacherStudentDrillDown {
  student: { id: number; name: string; email: string };
  shared_course: { id: number; name: string };
  attendance: {
    total: number; present: number; absent: number; late: number; percent: number;
  };
  grades_history: Array<{
    id: number; subject: string; marks: number; total_marks: number;
    exam_type: string | null; graded_at: string; pct: number;
  }>;
  course_grades: Array<{
    course_id: number; course_name: string; avg_score: number; count: number;
  }>;
  submissions: { total: number; graded: number; pending: number };
  gamification_points: number;
}

export interface StudentUpcomingDeadline {
  id: number;
  title: string;
  description: string | null;
  due_date: string;
  max_score: number | null;
  course_id: number;
  course_name: string;
  subject_name: string | null;
  teacher_name: string | null;
  days_until_due: number;
  urgency: 'urgent' | 'soon' | 'normal';
}

export interface ParentFeesForChild {
  summary: {
    total_fees: number;
    total_paid: number;
    total_outstanding: number;
    paid_count: number;
    pending_count: number;
    overdue_count: number;
  };
  items: Array<{
    id: number;
    amount: number;
    paid_amount: number;
    status: string;
    due_date: string | null;
    created_at: string;
    description: string | null;
    term: string | null;
    academic_year: string | null;
    paid_percent: number;
    outstanding: number;
  }>;
}

// ---------- State ---------------------------------------------------------

interface DashboardState {
  loading: boolean;
  error: string | null;
  accessDenied: boolean;
  admin: AdminDashboardData | null;
  teacher: TeacherDashboardData | null;
  student: StudentDashboardData | null;
  parent: ParentDashboardData | null;
  lastFetchedAt: number | null;

  // Phase 2 analytics state
  infrastructureHealth: InfrastructureHealth | null;
  gradeDistributionBySubject: SubjectGradeDistribution[];
  teacherOutliers: TeacherOutlier[];
  teacherStudentDetail: TeacherStudentDrillDown | null;
  studentUpcomingDeadlines: StudentUpcomingDeadline[];
  parentDeadlinesByChild: Record<number, StudentUpcomingDeadline[]>;
  parentFeesByChild: Record<number, ParentFeesForChild>;

  fetchAdmin: () => Promise<void>;
  fetchTeacher: () => Promise<void>;
  fetchStudent: () => Promise<void>;
  fetchParent: () => Promise<void>;

  // Phase 2 fetchers
  fetchInfrastructureHealth: () => Promise<void>;
  fetchGradeDistributionBySubject: (limit?: number) => Promise<void>;
  fetchTeacherOutliers: (courseId?: number) => Promise<void>;
  fetchTeacherStudentDetail: (studentId: number) => Promise<void>;
  fetchStudentUpcomingDeadlines: () => Promise<void>;
  fetchParentDeadlines: (studentId: number) => Promise<void>;
  fetchParentFees: (studentId: number) => Promise<void>;

  reset: () => void;
}

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

export const useDashboardStore = create<DashboardState>((set, _get) => ({
  loading: false,
  error: null,
  accessDenied: false,
  admin: null,
  teacher: null,
  student: null,
  parent: null,
  lastFetchedAt: null,
  infrastructureHealth: null,
  gradeDistributionBySubject: [],
  teacherOutliers: [],
  teacherStudentDetail: null,
  studentUpcomingDeadlines: [],
  parentDeadlinesByChild: {},
  parentFeesByChild: {},

  fetchAdmin: async () => {
    set({ loading: true, error: null, accessDenied: false });
    try {
      const res = await api.get('/dashboard/admin');
      const payload = res.data as AdminDashboardData;
      set({
        admin: payload,
        loading: false,
        accessDenied: false,
        error: null,
        lastFetchedAt: Date.now(),
      });
    } catch (err: any) {
      const status = err?.response?.status;
      const msg = err?.response?.data?.error || err?.message || 'Failed to load admin dashboard';
      if (status === 401 || status === 403) {
        set({
          loading: false,
          accessDenied: true,
          error: msg,
          admin: null,
        });
        return;
      }
      set({ loading: false, error: msg, admin: null });
    }
  },

  fetchTeacher: async () => {
    set({ loading: true, error: null, accessDenied: false });
    try {
      const res = await api.get('/dashboard/teacher');
      const payload = res.data as TeacherDashboardData;
      set({
        teacher: payload,
        loading: false,
        accessDenied: false,
        error: null,
        lastFetchedAt: Date.now(),
      });
    } catch (err: any) {
      const status = err?.response?.status;
      const msg = err?.response?.data?.error || err?.message || 'Failed to load teacher dashboard';
      if (status === 401 || status === 403) {
        set({
          loading: false,
          accessDenied: true,
          error: msg,
          teacher: null,
        });
        return;
      }
      set({ loading: false, error: msg, teacher: null });
    }
  },

  fetchStudent: async () => {
    set({ loading: true, error: null, accessDenied: false });
    try {
      const res = await api.get('/dashboard/student');
      const payload = res.data as StudentDashboardData;
      set({
        student: payload,
        loading: false,
        accessDenied: false,
        error: null,
        lastFetchedAt: Date.now(),
      });
    } catch (err: any) {
      const status = err?.response?.status;
      const msg = err?.response?.data?.error || err?.message || 'Failed to load student dashboard';
      if (status === 401 || status === 403) {
        set({
          loading: false,
          accessDenied: true,
          error: msg,
          student: null,
        });
        return;
      }
      set({ loading: false, error: msg, student: null });
    }
  },

  fetchParent: async () => {
    set({ loading: true, error: null, accessDenied: false });
    try {
      const res = await api.get('/dashboard/parent');
      const payload = res.data as ParentDashboardData;
      set({
        parent: payload,
        loading: false,
        accessDenied: false,
        error: null,
        lastFetchedAt: Date.now(),
      });
    } catch (err: any) {
      const status = err?.response?.status;
      const msg = err?.response?.data?.error || err?.message || 'Failed to load parent dashboard';
      if (status === 401 || status === 403) {
        set({
          loading: false,
          accessDenied: true,
          error: msg,
          parent: null,
        });
        return;
      }
      set({ loading: false, error: msg, parent: null });
    }
  },

  reset: () => {
    set({
      loading: false,
      error: null,
      accessDenied: false,
      admin: null,
      teacher: null,
      student: null,
      parent: null,
      lastFetchedAt: null,
      infrastructureHealth: null,
      gradeDistributionBySubject: [],
      teacherOutliers: [],
      teacherStudentDetail: null,
      studentUpcomingDeadlines: [],
      parentDeadlinesByChild: {},
      parentFeesByChild: {},
    });
  },

  // ============ Phase 2 fetchers ============

  fetchInfrastructureHealth: async () => {
    try {
      const res = await api.get('/dashboard/admin/infrastructure-health');
      set({ infrastructureHealth: res.data as InfrastructureHealth });
    } catch (err: any) {
      console.error('infrastructure-health fetch failed', err);
    }
  },

  fetchGradeDistributionBySubject: async (limit = 10) => {
    try {
      const res = await api.get(`/dashboard/admin/grade-distribution-by-subject?limit=${limit}`);
      set({ gradeDistributionBySubject: res.data as SubjectGradeDistribution[] });
    } catch (err: any) {
      console.error('grade-distribution-by-subject fetch failed', err);
    }
  },

  fetchTeacherOutliers: async (courseId?: number) => {
    try {
      const url = courseId
        ? `/dashboard/teacher/outliers?course_id=${courseId}`
        : '/dashboard/teacher/outliers';
      const res = await api.get(url);
      set({ teacherOutliers: res.data as TeacherOutlier[] });
    } catch (err: any) {
      console.error('teacher/outliers fetch failed', err);
      set({ teacherOutliers: [] });
    }
  },

  fetchTeacherStudentDetail: async (studentId: number) => {
    try {
      const res = await api.get(`/dashboard/teacher/student/${studentId}`);
      set({ teacherStudentDetail: res.data as TeacherStudentDrillDown });
    } catch (err: any) {
      console.error('teacher/student detail fetch failed', err);
      set({ teacherStudentDetail: null });
    }
  },

  fetchStudentUpcomingDeadlines: async () => {
    try {
      const res = await api.get('/dashboard/student/upcoming-deadlines');
      set({ studentUpcomingDeadlines: res.data as StudentUpcomingDeadline[] });
    } catch (err: any) {
      console.error('student upcoming-deadlines fetch failed', err);
      set({ studentUpcomingDeadlines: [] });
    }
  },

  fetchParentDeadlines: async (studentId: number) => {
    try {
      const res = await api.get(`/dashboard/parent/upcoming-deadlines/${studentId}`);
      const all = _get().parentDeadlinesByChild;
      set({
        parentDeadlinesByChild: {
          ...all,
          [studentId]: res.data as StudentUpcomingDeadline[],
        },
      });
    } catch (err: any) {
      console.error('parent upcoming-deadlines fetch failed', err);
    }
  },

  fetchParentFees: async (studentId: number) => {
    try {
      const res = await api.get(`/dashboard/parent/fees/${studentId}`);
      const all = _get().parentFeesByChild;
      set({
        parentFeesByChild: {
          ...all,
          [studentId]: res.data as ParentFeesForChild,
        },
      });
    } catch (err: any) {
      console.error('parent fees fetch failed', err);
    }
  },
}));

export default useDashboardStore;
