// frontend/src/pages/Tournament.tsx

import { type SetData } from '../types';
import { CalendarDays, Loader2, Network, SlidersHorizontal } from 'lucide-react';
import React, { useEffect, useRef, useState } from 'react';
import { useOutletContext, useParams } from 'react-router-dom';
import BracketView from '../components/Bracket/BracketView';
import TournamentForm from '../components/Forms/TournamentForm';
import ScheduleView from '../components/Schedule/ScheduleView';
import ScoreModal from '../components/Tournament/ScoreModal';
import Modal from '../components/UI/Modal';
import api, { WS_URL } from '../services/api';

// --- Type Definitions ---
interface Team { id: string | number; name: string; }
interface Court { id: string | number; name: string; }

interface RawMatch {
    id: string | number;
    bracket_type: string;
    round_number: number;
    match_number: number;
    winner_next_match_id?: string | number | null;
    winner_next_match_slot?: number | null;
    loser_next_match_id?: string | number | null;
    loser_next_match_slot?: number | null;
    p1_team_id?: string | number | null;
    p2_team_id?: string | number | null;
    winner_team_id?: string | number | null;
    ref_team_id?: string | number | null;
    ref_label?: string | null;
    ref_team?: { id: string | number; name: string } | null;
    status: string;
    court_id: string | number;
    start_time?: string;
    sets?: { p1: number; p2: number }[];
}

export interface ProcessedMatch extends Omit<RawMatch, 'ref_label' | 'ref_team'> {
    bracket: string;
    round: number;
    number: number;
    p1: string;
    p2: string;
    winnerName: string | null;
    p1_is_real: boolean;
    p2_is_real: boolean;
    isReady: boolean;
    court: string;
    time: string;
    p1_sets: number;
    p2_sets: number;
    hasTeams: boolean;
    isFinished: boolean;
    ref_label?: string;
    ref_team?: { id: string | number; name: string };
}

interface OutletContextType {
    setNavTitle: (title: string) => void;
    setNavSubtitle: (subtitle: string) => void;
    role: 'admin' | 'ref' | null;
}

export default function Tournament() {
    const { id } = useParams<{ id: string }>();
    const { setNavTitle, setNavSubtitle, role } = useOutletContext<OutletContextType>();

    const [matches, setMatches] = useState<ProcessedMatch[]>([]);
    const [view, setView] = useState<string>(() => localStorage.getItem('volley_view') || 'bracket');
    const [loading, setLoading] = useState<boolean>(true);
    const [showSettings, setShowSettings] = useState<boolean>(false);
    const [scoreMatch, setScoreMatch] = useState<ProcessedMatch | null>(null);
    const wsRef = useRef<WebSocket | null>(null);

    const handleViewChange = (newView: string) => {
        setView(newView);
        localStorage.setItem('volley_view', newView);
    };

    const processMatches = (rawMatches: RawMatch[], courts: Court[], teams: Team[]): ProcessedMatch[] => {
        if (!rawMatches) return [];

        const gf1 = rawMatches.find(m =>
            m.bracket_type === 'Finals' &&
            m.winner_next_match_id &&
            m.winner_next_match_id === m.loser_next_match_id
        );

        let skippedResetMatchId: string | number | null = null;
        if (gf1 && gf1.status === 'Finished' && gf1.winner_team_id === gf1.p1_team_id) {
            skippedResetMatchId = gf1.winner_next_match_id || null;
        }

        const courtMap: Record<string | number, string> = Object.fromEntries(courts.map(c => [c.id, c.name]));
        const teamMap: Record<string | number, string> = Object.fromEntries(teams.map(t => [t.id, t.name]));

        return rawMatches
            .filter(m => m.id !== skippedResetMatchId)
            .map(m => {

                // BUG 1 FIX: Explicitly check the SLOT (0 for top, 1 for bottom) 
                // to prevent duplicated labels.
                const getPlaceholder = (slot: number) => {
                    const winParent = rawMatches.find(rm => rm.winner_next_match_id === m.id && rm.winner_next_match_slot === slot);
                    if (winParent) return `Winner of #${winParent.match_number}`;

                    const loseParent = rawMatches.find(rm => rm.loser_next_match_id === m.id && rm.loser_next_match_slot === slot);
                    if (loseParent) return `Loser of #${loseParent.match_number}`;

                    return 'TBD';
                };

                const p1 = m.p1_team_id ? teamMap[m.p1_team_id] : getPlaceholder(0);
                const p2 = m.p2_team_id ? teamMap[m.p2_team_id] : getPlaceholder(1);

                // BUG 2 FIX: Resolve Backend Graph Links ("W:uuid" / "L:uuid") for Referees
                let resolvedRefLabel = m.ref_label;
                if (resolvedRefLabel && resolvedRefLabel.includes(':')) {
                    const [outcome, refId] = resolvedRefLabel.split(':');
                    const refMatch = rawMatches.find(rm => String(rm.id) === String(refId));
                    if (refMatch) {
                        resolvedRefLabel = `${outcome === 'W' ? 'Winner' : 'Loser'} of #${refMatch.match_number}`;
                    }
                }

                const hasTeams = !!(m.p1_team_id && m.p2_team_id);
                const isFinished = m.status === "Finished";
                const isReady = hasTeams && !isFinished;
                const winnerName = m.winner_team_id ? teamMap[m.winner_team_id] : null;

                return {
                    ...m,
                    ref_label: resolvedRefLabel || undefined,
                    ref_team: m.ref_team || undefined,
                    bracket: m.bracket_type,
                    round: m.round_number,
                    number: m.match_number,
                    p1,
                    p2,
                    winnerName,
                    p1_is_real: !!m.p1_team_id,
                    p2_is_real: !!m.p2_team_id,
                    isReady,
                    court: courtMap[m.court_id] || 'TBD',
                    time: m.start_time ? new Date(m.start_time).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) : '',
                    p1_sets: m.sets?.filter(s => s.p1 > s.p2).length || 0,
                    p2_sets: m.sets?.filter(s => s.p2 > s.p1).length || 0,
                    hasTeams,
                    isFinished
                };
            });
    };

    const fetchData = React.useCallback(async () => {
        try {
            const res = await api.get<{ name: string, timestamp: string, matches: RawMatch[], courts: Court[], teams: Team[] }>(`/tournaments/${id}`);
            setNavTitle(res.name);
            setNavSubtitle(new Date(res.timestamp).toLocaleDateString());
            setMatches(processMatches(res.matches, res.courts, res.teams));
        } catch (err) {
            console.error(err);
        } finally {
            setLoading(false);
        }
    }, [id, setNavTitle, setNavSubtitle]);

    useEffect(() => {
        (async () => {
            await fetchData();
        })();

        let reconnectTimeout: ReturnType<typeof setTimeout>;

        const connect = () => {
            const ws = new WebSocket(WS_URL);
            wsRef.current = ws;
            ws.onmessage = (e: MessageEvent) => {
                const msg = JSON.parse(e.data);
                if (msg.type === 'tournament_update' && msg.id === id) {
                    (async () => {
                        await fetchData();
                    })();
                }
            };
            ws.onclose = () => {
                wsRef.current = null;
                reconnectTimeout = setTimeout(connect, 3000);
            };
        };
        connect();

        const handleVisibilityChange = () => {
            if (document.visibilityState === 'visible') {
                (async () => {
                    await fetchData();
                })();
                if (!wsRef.current || wsRef.current.readyState === WebSocket.CLOSED) {
                    clearTimeout(reconnectTimeout);
                    connect();
                }
            }
        };
        document.addEventListener('visibilitychange', handleVisibilityChange);

        return () => {
            clearTimeout(reconnectTimeout);
            document.removeEventListener('visibilitychange', handleVisibilityChange);
            if (wsRef.current) {
                wsRef.current.onclose = null;
                wsRef.current.close();
                wsRef.current = null;
            }
        };
    }, [id, fetchData]);

    const handleDeleteTournament = async (tId: string | number) => {
        if (window.confirm("Purge this tournament?")) {
            await api.delete(`/tournaments/${tId}`);
            window.location.href = '/';
        }
    };

    if (loading) return <div className="flex h-full items-center justify-center"><Loader2 className="animate-spin text-orange-600" size={48} /></div>;

    return (
        <div className="h-full flex flex-col print:h-auto print:block">
            <div className="border-b border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-900 px-6 py-3 flex justify-between items-center shrink-0 z-20 print:hidden">
                <div className="flex gap-2">
                    <button onClick={() => handleViewChange('bracket')} className={`flex items-center gap-2 px-4 py-2 rounded-xl text-xs font-black uppercase tracking-wider transition ${view === 'bracket' ? 'bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-400' : 'text-zinc-500 hover:bg-zinc-100 dark:hover:bg-zinc-800'}`}>
                        <Network size={16} /> Bracket
                    </button>
                    <button onClick={() => handleViewChange('schedule')} className={`flex items-center gap-2 px-4 py-2 rounded-xl text-xs font-black uppercase tracking-wider transition ${view === 'schedule' ? 'bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-400' : 'text-zinc-500 hover:bg-zinc-100 dark:hover:bg-zinc-800'}`}>
                        <CalendarDays size={16} /> Schedule
                    </button>
                </div>
                {role === 'admin' && (
                    <button onClick={() => setShowSettings(true)} className="p-2 text-zinc-400 hover:text-orange-600 transition rounded-lg hover:bg-zinc-100 dark:hover:bg-zinc-800">
                        <SlidersHorizontal size={20} />
                    </button>
                )}
            </div>

            <div className="flex-1 overflow-hidden relative print:overflow-visible print:h-auto print:block">
                {view === 'bracket'
                    ? <BracketView matches={matches} onMatchClick={(m) => setScoreMatch(m as ProcessedMatch)} />
                    : <ScheduleView schedule={matches} onMatchClick={(m) => setScoreMatch(m as ProcessedMatch)} />
                }
            </div>

            {scoreMatch && (
                <ScoreModal
                    isOpen={!!scoreMatch}
                    onClose={() => setScoreMatch(null)}
                    match={scoreMatch}
                    isAuthenticated={!!role}
                    onClear={async (mid: string | number, c: string) => {
                        await api.delete(`/tournaments/${id}/matches/${mid}/score?code=${encodeURIComponent(c || '')}`);
                        setScoreMatch(null);
                    }}
                    onSubmit={async (mid: string | number, s: SetData[], c: string) => {
                        const method = scoreMatch.isFinished ? 'patch' : 'post';
                        await api[method](`/tournaments/${id}/matches/${mid}/score`, { sets: s, code: c });
                        setScoreMatch(null);
                    }}
                />
            )}
            <Modal isOpen={showSettings} onClose={() => setShowSettings(false)} title="Edit Tournament">
                <TournamentForm tournamentId={id} onSuccess={() => { setShowSettings(false); fetchData(); }} onDelete={handleDeleteTournament} />
            </Modal>
        </div>
    );
}