import clsx from "clsx";
import { useEffect, useState } from "preact/hooks";
import { useHordeState } from "../../contexts/state";
import { fetchLeaderboard, type LeaderboardEntry } from "../../utils/api";
import { formatNumber, formatTime } from "@common/utils";
import { Modal } from "@common/components/modal/Modal";
import modalStyles from "../../assets/modal.module.css";
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 totalUptime = ownWorkers.reduce((s, w) => s + w.uptime, 0);
    const totalGenerated = ownWorkers.reduce((s, w) => s + (w.kudos_details?.generated ?? 0), 0);
    const kudosPerHour = totalUptime > 0 ? (totalGenerated / totalUptime) * 3600 : 0;

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

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

        const load = async () => {
            setLoading(true);
            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) setLoading(false);
            }
        };

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

    return (
        <Modal open={open} onClose={onClose} class={clsx(modalStyles.modal, styles.modal)}>
            <div class={modalStyles.header}>
                <span class={modalStyles.title}>Leaderboard</span>
            </div>
            <div class={modalStyles.body}>
                {loading && <p class={styles.loading}>Loading…</p>}
                {error && <p class={styles.error}>{error}</p>}
                {!loading && !error && rows.length > 0 && (
                    <table class={styles.table}>
                        <thead>
                            <tr>
                                <th>#</th>
                                <th>Username</th>
                                <th>Kudos</th>
                                {user && <th>Diff</th>}
                            </tr>
                        </thead>
                        <tbody>
                            {rows.map(r => (
                                <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={clsx(r.diff !== undefined && (r.diff > 0 ? styles.above : styles.below))}>
                                            {r.diff !== undefined ? `+${formatNumber(r.diff)}` : '—'}
                                        </td>
                                    )}
                                </tr>
                            ))}
                        </tbody>
                    </table>
                )}
            </div>
            {(() => {
                if (!user || rows.length < 2 || kudosPerHour <= 0) return null;
                const nextRow = rows[rows.length - 2];
                if (!nextRow.diff || nextRow.diff <= 0) return null;
                const secs = Math.ceil((nextRow.diff / kudosPerHour) * 3600);
                return (
                    <div class={modalStyles.footer}>
                        <span class={styles.nextPlace}>
                            Time to #{nextRow.rank}: <strong>{formatTime(secs)}</strong>
                            <span class={styles.nextPlaceMeta}> ({formatNumber(Math.round(kudosPerHour))} kudos/h)</span>
                        </span>
                    </div>
                );
            })()}
        </Modal>
    );
};
