import { create } from 'zustand';
import { format } from 'date-fns';
import { sprintRacesApi } from '@/lib/apiClient';

export interface SprintRace {
  id: number;
  name: string;
  distance: string;
  date: string;
  rounds: RaceRound[];
  status: 'pending' | 'ongoing' | 'completed';
}

export interface RaceParticipant {
  studentId: number;
  studentName: string;
  position: number | null;
  timeSeconds: number | null;
  timeDisplay: string | null;
  status: 'finished' | 'dnf' | 'pending';
}

export interface RaceRound {
  roundNumber: number;
  participants: RaceParticipant[];
  startedAt: string | null;
  completedAt: string | null;
}

interface SprintRaceState {
  races: SprintRace[];
  currentRace: SprintRace | null;
  currentRound: number;
  isTimerRunning: boolean;
  elapsedMs: number;
  timerInterval: ReturnType<typeof setInterval> | null;

  fetchRaces: () => Promise<void>;
  createRace: (name: string, distance: string, studentIds: number[], studentNames: string[]) => Promise<SprintRace>;
  startTimer: () => void;
  stopTimer: () => void;
  tick: () => void;
  resetTimer: () => void;
  recordFinish: (studentId: number, position: number) => void;
  markDNF: (studentId: number) => void;
  saveRound: (lapData?: { studentId: number; position: number; timeSeconds: number; timeDisplay: string; status: 'finished' | 'dnf' }[]) => Promise<void>;
  startNewRound: () => void;
  addManualTiming: (studentId: number, position: number, timeDisplay: string) => void;
  editGroup: (studentIds: number[], studentNames: string[]) => void;
  getRaceById: (id: number) => SprintRace | undefined;
  getStudentRaces: (studentId: number) => { race: SprintRace; rounds: { roundNumber: number; participant: RaceParticipant }[] }[];
  deleteRace: (id: number) => Promise<void>;
}

let raceIdCounter = 1;

// No demo data - starts empty for real data
const demoRaces: SprintRace[] = [];

function mapApiRace(r: Record<string, unknown>): SprintRace {
  const rounds = (r.rounds as Record<string, unknown>[] ?? []).map((round: Record<string, unknown>) => ({
    roundNumber: Number(round.round_number ?? round.roundNumber ?? 1),
    startedAt: round.started_at ? String(round.started_at) : null,
    completedAt: round.completed_at ? String(round.completed_at) : null,
    participants: ((round.participants ?? []) as Record<string, unknown>[]).map((p: Record<string, unknown>) => ({
      studentId: Number(p.student_id ?? p.studentId ?? 0),
      studentName: String(p.student_name ?? p.studentName ?? ''),
      position: p.position ? Number(p.position) : null,
      timeSeconds: p.time_seconds ? Number(p.time_seconds) : null,
      timeDisplay: p.time_display ? String(p.time_display) : null,
      status: (p.status ?? 'pending') as 'finished' | 'dnf' | 'pending',
    })),
  }));

  return {
    id: Number(r.id ?? 0),
    name: String(r.name ?? ''),
    distance: String(r.distance ?? '500m'),
    date: String(r.race_date ?? r.date ?? ''),
    status: (r.status ?? 'pending') as 'pending' | 'ongoing' | 'completed',
    rounds,
  };
}

export const useSprintRaceStore = create<SprintRaceState>((set, get) => ({
  races: [],
  currentRace: null,
  currentRound: 1,
  isTimerRunning: false,
  elapsedMs: 0,
  timerInterval: null,

  fetchRaces: async () => {
    try {
      const data = await sprintRacesApi.getAll();
      if (Array.isArray(data)) {
        set({ races: data.map(mapApiRace) });
      }
    } catch {
      set({ races: demoRaces });
    }
  },

  createRace: async (name, distance, studentIds, studentNames) => {
    try {
      const result = await sprintRacesApi.create({
        name,
        distance,
        date: format(new Date(), 'yyyy-MM-dd'),
        participants: studentIds.map((id, i) => ({ studentId: id, studentName: studentNames[i] })),
      });
      if (result.success) {
        await get().fetchRaces();
      }
    } catch {
      // Offline fallback
    }

    // Local fallback
    const participants: RaceParticipant[] = studentIds.map((id, i) => ({
      studentId: id,
      studentName: studentNames[i],
      position: null,
      timeSeconds: null,
      timeDisplay: null,
      status: 'pending' as const,
    }));

    const newRace: SprintRace = {
      id: raceIdCounter++,
      name,
      distance,
      date: format(new Date(), 'yyyy-MM-dd'),
      rounds: [{ roundNumber: 1, participants, startedAt: null, completedAt: null }],
      status: 'pending',
    };

    set({ races: [...get().races, newRace], currentRace: newRace, currentRound: 1, elapsedMs: 0 });
    return newRace;
  },

  startTimer: () => {
    set({ isTimerRunning: true, elapsedMs: 0 });
    const interval = setInterval(() => {
      set(state => ({ elapsedMs: state.elapsedMs + 10 }));
    }, 10);
    set({ timerInterval: interval });
  },

  stopTimer: () => {
    const state = get();
    if (state.timerInterval) clearInterval(state.timerInterval);
    set({ isTimerRunning: false, timerInterval: null });
  },

  tick: () => set(state => ({ elapsedMs: state.elapsedMs + 10 })),

  resetTimer: () => {
    const state = get();
    if (state.timerInterval) clearInterval(state.timerInterval);
    set({ isTimerRunning: false, elapsedMs: 0, timerInterval: null });
  },

  recordFinish: (studentId, position) => {
    const state = get();
    if (!state.currentRace) return;

    const elapsedSec = state.elapsedMs / 1000;
    const mins = Math.floor(elapsedSec / 60);
    const secs = elapsedSec % 60;
    const timeDisplay = mins > 0
      ? `${String(mins).padStart(2, '0')}:${String(Math.floor(secs)).padStart(2, '0')}.${String(Math.floor((secs % 1) * 100)).padStart(2, '0')}`
      : `${String(Math.floor(secs)).padStart(2, '0')}.${String(Math.floor((secs % 1) * 100)).padStart(2, '0')}`;

    set({
      currentRace: {
        ...state.currentRace,
        rounds: state.currentRace.rounds.map(r =>
          r.roundNumber === state.currentRound
            ? {
                ...r,
                participants: r.participants.map(p =>
                  p.studentId === studentId
                    ? { ...p, position, timeSeconds: elapsedSec, timeDisplay, status: 'finished' as const }
                    : p
                ),
              }
            : r
        ),
        status: 'ongoing',
      },
    });
  },

  markDNF: (studentId) => {
    const state = get();
    if (!state.currentRace) return;

    set({
      currentRace: {
        ...state.currentRace,
        rounds: state.currentRace.rounds.map(r =>
          r.roundNumber === state.currentRound
            ? {
                ...r,
                participants: r.participants.map(p =>
                  p.studentId === studentId ? { ...p, status: 'dnf' as const, position: null, timeSeconds: null, timeDisplay: null } : p
                ),
              }
            : r
        ),
      },
    });
  },

  saveRound: async (lapData) => {
    const state = get();
    if (!state.currentRace) return;

    // Build results for API
    const results = lapData?.map(l => ({
      studentId: l.studentId,
      position: l.position,
      timeSeconds: l.timeSeconds,
      timeDisplay: l.timeDisplay,
      status: l.status,
    })) ?? [];

    // Also include DNF students
    const currentParticipants = state.currentRace.rounds.find(r => r.roundNumber === state.currentRound)?.participants || [];
    const dnfStudents = currentParticipants.filter(p => !results.some(r => r.studentId === p.studentId));
    dnfStudents.forEach(p => {
      results.push({ studentId: p.studentId, position: 0, timeSeconds: 0, timeDisplay: 'DNF', status: 'dnf' as const });
    });

    try {
      await sprintRacesApi.saveRound({
        raceId: state.currentRace.id,
        roundId: state.currentRound,
        results,
      });
      await get().fetchRaces();
    } catch {
      // Offline - update local state
    }

    let updatedParticipants = state.currentRace.rounds.find(r => r.roundNumber === state.currentRound)?.participants || [];

    if (lapData && lapData.length > 0) {
      updatedParticipants = updatedParticipants.map(p => {
        const lap = lapData.find(l => l.studentId === p.studentId);
        if (lap) {
          return { ...p, position: lap.position, timeSeconds: lap.timeSeconds, timeDisplay: lap.timeDisplay, status: lap.status };
        }
        return { ...p, status: 'dnf' as const, position: null, timeSeconds: null, timeDisplay: null };
      });
    }

    const updatedRace = {
      ...state.currentRace,
      rounds: state.currentRace.rounds.map(r =>
        r.roundNumber === state.currentRound
          ? { ...r, participants: updatedParticipants, completedAt: format(new Date(), 'HH:mm:ss') }
          : r
      ),
      status: 'completed' as const,
    };

    set({
      currentRace: updatedRace,
      races: state.races.map(r => r.id === updatedRace.id ? updatedRace : r),
    });
  },

  startNewRound: () => {
    const state = get();
    if (!state.currentRace) return;

    const nextRound = state.currentRound + 1;
    const prevParticipants = state.currentRace.rounds[state.currentRace.rounds.length - 1].participants;

    set({
      currentRound: nextRound,
      currentRace: {
        ...state.currentRace,
        rounds: [
          ...state.currentRace.rounds,
          {
            roundNumber: nextRound,
            participants: prevParticipants.map(p => ({
              ...p,
              position: null,
              timeSeconds: null,
              timeDisplay: null,
              status: 'pending' as const,
            })),
            startedAt: null,
            completedAt: null,
          },
        ],
      },
    });
  },

  editGroup: (studentIds, studentNames) => {
    const state = get();
    if (!state.currentRace) return;

    const participants: RaceParticipant[] = studentIds.map((id, i) => ({
      studentId: id,
      studentName: studentNames[i],
      position: null,
      timeSeconds: null,
      timeDisplay: null,
      status: 'pending' as const,
    }));

    set({
      currentRace: {
        ...state.currentRace,
        rounds: state.currentRace.rounds.map((r, i) =>
          i === state.currentRace!.rounds.length - 1 ? { ...r, participants } : r
        ),
      },
    });
  },

  addManualTiming: (studentId, position, timeDisplay) => {
    const state = get();
    if (!state.currentRace) return;

    const parts = timeDisplay.split(':');
    let timeSeconds = 0;
    if (parts.length === 2) {
      timeSeconds = parseInt(parts[0]) * 60 + parseFloat(parts[1]);
    } else {
      timeSeconds = parseFloat(parts[0]);
    }

    set({
      currentRace: {
        ...state.currentRace,
        rounds: state.currentRace.rounds.map(r =>
          r.roundNumber === state.currentRound
            ? {
                ...r,
                participants: r.participants.map(p =>
                  p.studentId === studentId
                    ? { ...p, position, timeSeconds, timeDisplay, status: 'finished' as const }
                    : p
                ),
              }
            : r
        ),
      },
    });
  },

  getRaceById: (id) => get().races.find(r => r.id === id),

  getStudentRaces: (studentId) => {
    return get().races.flatMap(race =>
      race.rounds.map(round => {
        const participant = round.participants.find(p => p.studentId === studentId);
        return participant && participant.status === 'finished'
          ? { race, rounds: [{ roundNumber: round.roundNumber, participant }] }
          : null;
      }).filter(Boolean) as { race: SprintRace; rounds: { roundNumber: number; participant: RaceParticipant }[] }[]
    );
  },

  deleteRace: async (id) => {
    try {
      await sprintRacesApi.delete(id);
      await get().fetchRaces();
    } catch {
      // Offline fallback
    }
    set({
      races: get().races.filter(r => r.id !== id),
      currentRace: get().currentRace?.id === id ? null : get().currentRace,
    });
  },
}));
