/**
 * Student Assignments Module - Zustand Store
 */

import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import api from './auth';
import type { Attachment } from './attachments';
import { createAxiosUploadProgressHandler } from '../lib/uploadProgress';

export interface Assignment {
  id: number;
  title: string;
  description: string;
  subject: string;
  class_id: number;
  class_name: string;
  teacher_id: number;
  teacher_name: string;
  due_date: string;
  total_marks: number;
  status: 'pending' | 'in_progress' | 'completed' | 'graded';
  attachments?: string[];
  instructions?: string;
}

export interface AssignmentDraft {
  assignment_id: number;
  content: string;
  file_name?: string;
  file_data?: string;
  saved_at: string;
}

interface AssignmentSubmission {
  id?: number;
  assignment_id: number;
  content: string;
  file_name?: string;
  file_data?: string;
  file_path?: string | null;        // legacy submissions.file_path column
  submitted_at?: string;
  marks?: number;
  max_marks?: number;
  feedback?: string;
  graded_at?: string;
  // PR 3 §6.1 / §6.4 / §7.1 — attachments and marked scripts joined by the
  // server so the student / parent UI can render downloads and previews
  // without an N+1 fetch. The legacy file_data/file_path fields stay populated
  // for any rows that pre-date the attachments table.
  attachments?: Attachment[];
  marked_scripts?: Attachment[];
  status?: 'submitted' | 'graded' | 'returned' | 'late' | string;
}

interface AssignmentStore {
  // State
  assignments: Assignment[];
  submissions: AssignmentSubmission[];
  drafts: Record<number, AssignmentDraft>; // keyed by assignment_id
  currentAssignment: Assignment | null;
  isLoading: boolean;
  isSubmitting: boolean;
  submissionProgress: number;
  error: string | null;

  // Actions - Assignments
  fetchAssignments: () => Promise<void>;
  fetchAssignment: (id: number) => Promise<void>;

  // Actions - Submissions
  submitAssignment: (assignmentId: number, data: Partial<AssignmentSubmission>) => Promise<void>;
  fetchSubmission: (assignmentId: number) => Promise<AssignmentSubmission | null>;

  // Actions - Drafts (local storage)
  saveDraft: (assignmentId: number, content: string, file?: { name: string; data: string }) => void;
  loadDraft: (assignmentId: number) => AssignmentDraft | null;
  deleteDraft: (assignmentId: number) => void;
  getDraftsCount: () => number;

  // Helpers
  getPendingAssignments: () => Assignment[];
  getInProgressAssignments: () => Assignment[];
  getCompletedAssignments: () => Assignment[];
  getOverdueAssignments: () => Assignment[];
  isOverdue: (dueDate: string) => boolean;
  getTimeRemaining: (dueDate: string) => string;
}

// Draft storage with persist middleware
interface DraftStore {
  drafts: Record<number, AssignmentDraft>;
  saveDraft: (assignmentId: number, content: string, file?: { name: string; data: string }) => void;
  loadDraft: (assignmentId: number) => AssignmentDraft | null;
  deleteDraft: (assignmentId: number) => void;
  getDraftsCount: () => number;
}

const useDraftStore = create<DraftStore>()(
  persist(
    (set, get) => ({
      drafts: {},

      saveDraft: (assignmentId, content, file) => {
        const draft: AssignmentDraft = {
          assignment_id: assignmentId,
          content,
          file_name: file?.name,
          file_data: file?.data,
          saved_at: new Date().toISOString(),
        };
        set(state => ({
          drafts: { ...state.drafts, [assignmentId]: draft },
        }));
      },

      loadDraft: (assignmentId) => {
        return get().drafts[assignmentId] || null;
      },

      deleteDraft: (assignmentId) => {
        set(state => {
          const { [assignmentId]: _, ...rest } = state.drafts;
          return { drafts: rest };
        });
      },

      getDraftsCount: () => {
        return Object.keys(get().drafts).length;
      },
    }),
    { name: 'assignment-drafts' }
  )
);

export const useAssignmentStore = create<AssignmentStore>((set, get) => ({
  assignments: [],
  submissions: [],
  drafts: {},
  currentAssignment: null,
  isLoading: false,
  isSubmitting: false,
  error: null,

  // ============ Assignments ============

  fetchAssignments: async () => {
    try {
      set({ isLoading: true, error: null });
      const response = await api.get('/assignments');
      set({ assignments: response.data, isLoading: false });
    } catch (error: any) {
      set({ error: error.message, isLoading: false });
      console.error('Failed to fetch assignments:', error);
    }
  },

  fetchAssignment: async (id) => {
    try {
      set({ isLoading: true, error: null });
      const response = await api.get(`/assignments/${id}`);
      set({ currentAssignment: response.data, isLoading: false });
    } catch (error: any) {
      set({ error: error.message, isLoading: false });
      console.error('Failed to fetch assignment:', error);
    }
  },

  // ============ Submissions ============

  submitAssignment: async (assignmentId, data) => {
    try {
      set({ isSubmitting: true, error: null });

      const formData = new FormData();
      formData.append('content', data.content || '');
      formData.append('assignment_id', String(assignmentId));
      if (data.file_name) {
        formData.append('file_name', data.file_name);
      }
      if (data.file_data) {
        // Convert base64 to blob if needed
        const byteCharacters = atob(data.file_data);
        const byteNumbers = new Array(byteCharacters.length);
        for (let i = 0; i < byteCharacters.length; i++) {
          byteNumbers[i] = byteCharacters.charCodeAt(i);
        }
        const byteArray = new Uint8Array(byteNumbers);
        const blob = new Blob([byteArray]);
        formData.append('file', blob, data.file_name || 'submission');
      }

      const response = await api.post(`/assignments/${assignmentId}/submit`, formData, {
        headers: { 'Content-Type': 'multipart/form-data' },
      });

      // Delete local draft after successful submission
      useDraftStore.getState().deleteDraft(assignmentId);

      // Update assignment status in local state
      set(state => ({
        submissions: [...state.submissions, response.data],
        assignments: state.assignments.map(a =>
          a.id === assignmentId ? { ...a, status: 'completed' as const } : a
        ),
        isSubmitting: false,
      }));

    } catch (error: any) {
      set({ error: error.response?.data?.error || error.message, isSubmitting: false });
      console.error('Failed to submit assignment:', error);
      throw error;
    }
  },

  fetchSubmission: async (assignmentId) => {
    try {
      const response = await api.get(`/assignments/${assignmentId}/submission`);
      if (response.data) {
        set(state => ({
          submissions: [
            ...state.submissions.filter(s => s.assignment_id !== assignmentId),
            response.data,
          ],
        }));
      }
      return response.data || null;
    } catch (error: any) {
      if (error.response?.status !== 404) {
        console.error('Failed to fetch submission:', error);
      }
      return null;
    }
  },

  // ============ Drafts (delegated to draft store) ============

  saveDraft: (assignmentId, content, file) => {
    useDraftStore.getState().saveDraft(assignmentId, content, file);
    set({ drafts: useDraftStore.getState().drafts });
  },

  loadDraft: (assignmentId) => {
    return useDraftStore.getState().loadDraft(assignmentId);
  },

  deleteDraft: (assignmentId) => {
    useDraftStore.getState().deleteDraft(assignmentId);
    set({ drafts: useDraftStore.getState().drafts });
  },

  getDraftsCount: () => {
    return useDraftStore.getState().getDraftsCount();
  },

  // ============ Helpers ============

  getPendingAssignments: () => {
    return get().assignments.filter(a => a.status === 'pending');
  },

  getInProgressAssignments: () => {
    return get().assignments.filter(a => a.status === 'in_progress');
  },

  getCompletedAssignments: () => {
    return get().assignments.filter(a => a.status === 'completed' || a.status === 'graded');
  },

  getOverdueAssignments: () => {
    const now = new Date();
    return get().assignments.filter(a => {
      if (a.status === 'completed' || a.status === 'graded') return false;
      const dueDate = new Date(a.due_date);
      return dueDate < now;
    });
  },

  isOverdue: (dueDate) => {
    return new Date(dueDate) < new Date();
  },

  getTimeRemaining: (dueDate) => {
    const now = new Date();
    const due = new Date(dueDate);
    const diff = due.getTime() - now.getTime();

    if (diff < 0) {
      const overdueDays = Math.ceil(Math.abs(diff) / (1000 * 60 * 60 * 24));
      return `${overdueDays} day${overdueDays > 1 ? 's' : ''} overdue`;
    }

    const days = Math.floor(diff / (1000 * 60 * 60 * 24));
    const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));

    if (days > 0) {
      return `${days} day${days > 1 ? 's' : ''} left`;
    }
    if (hours > 0) {
      return `${hours} hour${hours > 1 ? 's' : ''} left`;
    }

    const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
    return `${minutes} minute${minutes > 1 ? 's' : ''} left`;
  },
}));

// Export both stores
export { useDraftStore };
export default useAssignmentStore;