import { useEffect, useState } from "preact/hooks";
import { useBool } from "@common/hooks/useBool";
import { useHordeState } from "../../contexts/state";
import { fetchLeaderboard, type LeaderboardEntry } from "../../utils/api";
import { formatNumber, formatTime } from "@common/utils";
import { calculateTotalKudosPerHour } from "../../utils/calculations";
import { Modal } from "@common/components/Modal";
import styles from "../../assets/leaderboard-modal.module.css";

interface Props {
    open: boolean;
    onClose: () => void;
}

const PAGE_SIZE = 25;

export const LeaderboardModal = ({ open, onClose }: Props) => {
    const { state } = useHordeState();
    const { user, workers } = state;

    const ownWorkerIds = new Set(user?.worker_ids ?? []);
    const ownWorkers = workers.filter(w => ownWorkerIds.has(w.id));
    const kudosPerHour = calculateTotalKudosPerHour(ownWorkers);

    const [rows, setRows] = useState<(LeaderboardEntry & { rank: number; diff?: number })[]>([]);
    const loading = useBool(false);
    const [error, setError] = useState<string | null>(null);

    useEffect(() => {
        if (!open) return;
        let cancelled = false;

        const load = async () => {
            loading.setTrue();
            setError(null);
            try {
                if (!user) {
                    const page = await fetchLeaderboard(1);
                    if (!cancelled) {
                        setRows(page.slice(0, 10).map((e, i) => ({ ...e, rank: i + 1 })));
                    }
                } else {
                    let userRank = -1;
                    let page = 1;
                    outer: while (true) {
                        const entries = await fetchLeaderboard(page);
                        if (entries.length === 0) break;
                        for (let i = 0; i < entries.length; i++) {
                            if (entries[i].username === user.username) {
                                userRank = (page - 1) * PAGE_SIZE + i + 1;
                                break outer;
                            }
                        }
                        page++;
                        if (page > 20) break;
                    }

                    if (cancelled) return;

                    const startRank = Math.max(1, userRank - 10);
                    const startPage = Math.ceil(startRank / PAGE_SIZE);
                    const endPage = Math.ceil(userRank / PAGE_SIZE);

                    const collected: LeaderboardEntry[] = [];
                    for (let p = startPage; p <= endPage; p++) {
                        const entries = await fetchLeaderboard(p);
                        collected.push(...entries);
                    }

                    if (cancelled) return;

                    const userKudos = user.kudos;
                    const result = collected
                        .slice(startRank - (startPage - 1) * PAGE_SIZE - 1)
                        .slice(0, userRank - startRank + 1)
                        .map((e, i) => ({
                            ...e,
                            rank: startRank + i,
                            diff: e.username === user.username ? undefined : e.kudos - userKudos,
                        }));

                    setRows(result);
                }
            } catch (e) {
                if (!cancelled) setError(String(e));
            } finally {
                if (!cancelled) loading.setFalse();
            }
        };

        load();
        return () => { cancelled = true; };
    }, [open, user?.username]);

    const footer = user && kudosPerHour > 0
        ? <span class={styles.footer}>Kudos gathering speed: <strong>{formatNumber(Math.round(kudosPerHour))} kudos/h</strong></span>
        : undefined;

    return (
        <Modal open={open} onClose={onClose} title="Leaderboard" class={styles.modal} footer={footer}>
            {loading.value && <p class={styles.loading}>Loading…</p>}
            {error && <p class={styles.error}>{error}</p>}
            {!loading.value && !error && rows.length > 0 && (
                <table class={styles.table}>
                    <thead>
                        <tr>
                            <th>#</th>
                            <th>Username</th>
                            <th>Kudos</th>
                            {user && <th>Diff</th>}
                            {user && kudosPerHour > 0 && <th>Time</th>}
                        </tr>
                    </thead>
                    <tbody>
                        {rows.map(r => {
                            const remainingSecs = r.diff !== undefined && r.diff > 0 && kudosPerHour > 0
                                ? Math.ceil((r.diff / kudosPerHour) * 3600)
                                : undefined;
                            return (
                                <tr key={r.rank} class={r.username === user?.username ? styles.selfRow : undefined}>
                                    <td>{r.rank}</td>
                                    <td>{r.username}</td>
                                    <td>{formatNumber(r.kudos)}</td>
                                    {user && (
                                        <td class={r.diff !== undefined ? (r.diff > 0 ? styles.above : styles.below) : undefined}>
                                            {r.diff !== undefined ? `+${formatNumber(r.diff)}` : '—'}
                                        </td>
                                    )}
                                    {user && kudosPerHour > 0 && (
                                        <td class={styles.timeCol}>
                                            {r.username === user?.username
                                                ? '—'
                                                : remainingSecs !== undefined
                                                    ? formatTime(remainingSecs)
                                                    : '—'}
                                        </td>
                                    )}
                                </tr>
                            );
                        })}
                    </tbody>
                </table>
            )}
        </Modal>
    );
};
