/**
 * Crossword Puzzle Module - Zustand Store
 *
 * Talks to /api/crossword:
 *   GET    /games                list games (server applies visibility filter by role)
 *   GET    /games/:id            single game + clues + grid_layout (students get answers stripped)
 *   POST   /games                create draft + clues, server runs generator + persists
 *   POST   /games/:id/publish    owner/admin: set is_published=1
 *   POST   /sessions             student: start (idempotent - returns existing if in progress)
 *   PUT    /sessions/:id         student: debounced save of grid state (current_state)
 *   POST   /sessions/:id/submit  student: validate + award points
 *   GET    /sessions/me          student's own sessions
 *   GET    /leaderboard          top students by total points_earned
 */

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

export interface CrosswordCell {
  row: number;
  col: number;
  letter?: string;
  clue_ids?: number[];
  is_block: boolean;
}

export interface CrosswordPlacement {
  clue_id: number;
  clue_text: string;
  answer?: string;       // stripped for students
  direction: 'across' | 'down';
  start_row: number;
  start_col: number;
  clue_number: number;
}

export interface CrosswordClue {
  id: number;
  uid?: string;
  game_id: number;
  clue_text: string;
  answer?: string;       // stripped for students
  direction: 'across' | 'down';
  start_row: number;
  start_col: number;
  clue_number: number;
  hint?: string | null;
}

export interface CrosswordGame {
  id: number;
  uid?: string;
  title: string;
  description?: string | null;
  subject_id?: number | null;
  class_id?: number | null;
  created_by: number;
  status: 'draft' | 'ready' | 'archived';
  word_count: number;
  difficulty: 'easy' | 'medium' | 'hard';
  reward_points: number;
  time_limit_seconds?: number | null;
  is_published: number; // 0/1
  grid_layout?: {
    rows: number;
    cols: number;
    cells: CrosswordCell[];
    placements?: CrosswordPlacement[];
  } | null;
  clues?: CrosswordClue[];
  _permissions?: {
    canEdit?: boolean;
    canSeeAnswers?: boolean;
  };
  created_at?: string;
  updated_at?: string;
}

export interface CrosswordSession {
  id: number;
  uid?: string;
  game_id: number;
  student_id: number;
  current_state?: string | Record<string, string> | null;
  correct_count: number;
  total_count: number;
  points_earned: number;
  time_taken_seconds?: number | null;
  completed_at?: string | null;
  created_at?: string;
  updated_at?: string;
  game_title?: string;
  difficulty?: string;
  word_count?: number;
}

export interface SubmitSessionResult extends CrosswordSession {
  is_complete: boolean;
  per_clue?: Array<{
    clue_id: number;
    clue_text: string;
    direction: string;
    correct: boolean;
    expected?: string;
    submitted?: string;
  }>;
}

export interface LeaderboardRow {
  student_id: number;
  first_name: string;
  last_name: string;
  total_points: number;
  sessions_completed: number;
  perfect_completions: number;
}

export interface CrosswordDraftClueInput {
  clue_text: string;
  answer: string;
  direction?: 'across' | 'down';
  hint?: string;
}

interface CrosswordStore {
  // State
  games: CrosswordGame[];
  currentGame: CrosswordGame | null;
  sessions: CrosswordSession[];
  currentSession: CrosswordSession | null;
  leaderboard: LeaderboardRow[];
  isLoading: boolean;
  isSaving: boolean;        // debounced save flag
  error: string | null;

  // Games
  fetchGames: () => Promise<void>;
  fetchGame: (id: number) => Promise<CrosswordGame | null>;
  createGame: (data: {
    title: string;
    description?: string;
    subject_id?: number;
    class_id?: number;
    reward_points?: number;
    time_limit_seconds?: number | null;
    clues: CrosswordDraftClueInput[];
  }) => Promise<CrosswordGame>;
  publishGame: (id: number) => Promise<CrosswordGame>;
  deleteGame: (id: number) => Promise<void>;

  // Sessions (student)
  startSession: (gameId: number) => Promise<CrosswordSession>;
  updateSessionState: (sessionId: number, state: Record<string, string>) => Promise<void>;
  submitSession: (sessionId: number, finalState?: Record<string, string>) => Promise<SubmitSessionResult>;
  fetchMySessions: () => Promise<void>;

  // Leaderboard
  fetchLeaderboard: (limit?: number) => Promise<void>;

  // Local
  reset: () => void;
}

export const useCrosswordStore = create<CrosswordStore>((set, get) => ({
  games: [],
  currentGame: null,
  sessions: [],
  currentSession: null,
  leaderboard: [],
  isLoading: false,
  isSaving: false,
  error: null,

  // ============ GAMES ============

  fetchGames: async () => {
    try {
      set({ isLoading: true, error: null });
      const response = await api.get('/crossword/games');
      set({ games: response.data || [], isLoading: false });
    } catch (error: any) {
      set({ error: error.response?.data?.error || error.message, isLoading: false });
      console.error('Failed to fetch crossword games:', error);
    }
  },

  fetchGame: async (id) => {
    try {
      set({ isLoading: true, error: null });
      const response = await api.get(`/crossword/games/${id}`);
      set({ currentGame: response.data, isLoading: false });
      return response.data;
    } catch (error: any) {
      set({ error: error.response?.data?.error || error.message, isLoading: false });
      console.error('Failed to fetch crossword game:', error);
      return null;
    }
  },

  createGame: async (data) => {
    const response = await api.post('/crossword/games', data);
    const created = response.data;
    set(state => ({ games: [created, ...state.games] }));
    return created;
  },

  publishGame: async (id) => {
    const response = await api.post(`/crossword/games/${id}/publish`);
    set(state => ({
      games: state.games.map(g => (g.id === id ? response.data : g)),
      currentGame:
        state.currentGame?.id === id
          ? { ...state.currentGame, is_published: 1, ...response.data }
          : state.currentGame,
    }));
    return response.data;
  },

  deleteGame: async (id) => {
    await api.delete(`/crossword/games/${id}`);
    set(state => ({
      games: state.games.filter(g => g.id !== id),
      currentGame: state.currentGame?.id === id ? null : state.currentGame,
    }));
  },

  // ============ SESSIONS ============

  startSession: async (gameId) => {
    try {
      set({ error: null });
      const response = await api.post('/crossword/sessions', { game_id: gameId });
      const session = response.data;
      set(state => ({
        currentSession: session,
        // Keep an index of our sessions up to date too
        sessions: [
          session,
          ...state.sessions.filter(s => s.id !== session.id),
        ],
      }));
      return session;
    } catch (error: any) {
      set({ error: error.response?.data?.error || error.message });
      throw error;
    }
  },

  // Lightweight debounced save - last write wins on the server.
  // Caller (component) should debounce ~300ms before invoking this so we don't
  // hammer the API while the student types in the grid.
  updateSessionState: async (sessionId, state) => {
    try {
      set({ isSaving: true, error: null });
      const response = await api.put(`/crossword/sessions/${sessionId}`, {
        current_state: state,
      });
      const updated = response.data;
      set(s => ({
        currentSession:
          s.currentSession?.id === sessionId ? updated : s.currentSession,
        isSaving: false,
      }));
    } catch (error: any) {
      set({ error: error.response?.data?.error || error.message, isSaving: false });
      console.error('Failed to save session state:', error);
    }
  },

  submitSession: async (sessionId, finalState) => {
    const payload: Record<string, any> = {};
    if (finalState !== undefined) {
      payload.current_state = finalState;
    }
    const response = await api.post(`/crossword/sessions/${sessionId}/submit`, payload);
    const result = response.data;
    set(s => ({
      currentSession: result,
      sessions: s.sessions.map(x => (x.id === sessionId ? result : x)),
    }));
    return result as SubmitSessionResult;
  },

  fetchMySessions: async () => {
    try {
      set({ error: null });
      const response = await api.get('/crossword/sessions/me');
      set({ sessions: response.data || [] });
    } catch (error: any) {
      set({ error: error.response?.data?.error || error.message });
      console.error('Failed to fetch my sessions:', error);
    }
  },

  // ============ LEADERBOARD ============

  fetchLeaderboard: async (limit = 20) => {
    try {
      set({ error: null });
      const response = await api.get(`/crossword/leaderboard?limit=${limit}`);
      set({ leaderboard: response.data || [] });
    } catch (error: any) {
      set({ error: error.response?.data?.error || error.message });
      console.error('Failed to fetch leaderboard:', error);
    }
  },

  reset: () => {
    set({
      currentGame: null,
      currentSession: null,
      error: null,
    });
  },
}));

export default useCrosswordStore;
