import { Head, router } from '@inertiajs/react';
import {
    CalendarIcon,
    ChevronDown,
    Copy,
    LogOut,
    PanelLeftClose,
    PanelLeftOpen,
} from 'lucide-react';
import { useEffect, useMemo, useState } from 'react';
import { toast, Toaster } from 'sonner';
import { AppSidebar } from '@/components/AppSidebar';
import { Button } from '@/components/ui/button';
import { Calendar } from '@/components/ui/calendar';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { useAppSidebar } from '@/hooks/useAppSidebar';
import { route } from '@/lib/route';
import { cn } from '@/lib/utils';

type DomainOption = {
    id: number;
    account_name: string;
    domain: string;
};

type GameOption = {
    id: number;
    game_name: string;
};

type GameTypeOption = {
    name: string;
    fname: string;
};

type BidRow = {
    amount: number;
    bid_game_number: string;
    game_type: string;
    game_name: string;
};

type ReportFilters = {
    domain_id: string;
    game_id: string;
    game_type: string;
    date: string;
    open_close: string;
};

type ReportSummary = {
    game_name: string;
    domain_label: string;
    open_close: string;
    date: string;
    total_bet: number;
    total_amount: number;
};

const selectClassName =
    'h-9 w-full rounded-lg border border-border/80 bg-muted/40 px-3 text-sm shadow-none outline-none focus:border-border/80';

function parseLocalDate(isoDate: string): Date {
    const [y, m, d] = isoDate.split('-').map(Number);
    return new Date(y, (m ?? 1) - 1, d ?? 1);
}

function toIsoDate(date: Date): string {
    const y = date.getFullYear();
    const m = String(date.getMonth() + 1).padStart(2, '0');
    const d = String(date.getDate()).padStart(2, '0');
    return `${y}-${m}-${d}`;
}

function formatDisplayDate(isoDate: string): string {
    return parseLocalDate(isoDate).toLocaleDateString('en-GB', {
        day: '2-digit',
        month: 'short',
        year: 'numeric',
    });
}

function todayDate(): Date {
    const now = new Date();
    return new Date(now.getFullYear(), now.getMonth(), now.getDate());
}

function visitReport(params: Partial<ReportFilters> & { filter?: boolean }) {
    router.get(
        route('report'),
        {
            domain_id: params.domain_id ?? 'all',
            ...(params.game_id ? { game_id: params.game_id } : {}),
            ...(params.game_type ? { game_type: params.game_type } : {}),
            ...(params.date ? { date: params.date } : {}),
            ...(params.open_close ? { open_close: params.open_close } : {}),
            ...(params.filter ? { filter: 1 } : {}),
        },
        { preserveState: true, replace: true, preserveScroll: true },
    );
}

function formatCopyDate(isoDate: string): string {
    const [y, m, d] = isoDate.split('-');
    if (!y || !m || !d) {
        return isoDate;
    }

    return `${d}-${m}-${y}`;
}

function formatCopyAmount(amount: number): string {
    return String(Number(amount) || 0);
}

function sortRowsByBidNumber(rows: BidRow[]): BidRow[] {
    return [...rows].sort((a, b) => {
        const aNum = String(a.bid_game_number);
        const bNum = String(b.bid_game_number);
        if (aNum.length !== bNum.length) {
            return aNum.length - bNum.length;
        }

        return aNum.localeCompare(bNum, undefined, { numeric: true });
    });
}

function rowAmount(row: BidRow): number {
    return Number(row.amount) || 0;
}

function buildCopyText(
    typeLabel: string,
    gameName: string,
    openClose: string,
    date: string,
    rows: BidRow[],
): string {
    const sorted = sortRowsByBidNumber(rows);
    const total = sorted.reduce((sum, row) => sum + rowAmount(row), 0);

    return [
        gameName,
        `${typeLabel}-${openClose} Date :${date}`,
        ...sorted.map(
            (row) => `${row.bid_game_number} == ${formatCopyAmount(rowAmount(row))}`,
        ),
        `Total amount: ${formatCopyAmount(total)}`,
    ].join('\n');
}

function buildAllBidsCopyText(
    gameName: string,
    openClose: string,
    date: string,
    groups: { fname: string; rows: BidRow[] }[],
): string {
    const sections = groups.filter((group) => group.rows.length > 0);
    const grandTotal = sections.reduce(
        (sum, group) => sum + group.rows.reduce((groupSum, row) => groupSum + rowAmount(row), 0),
        0,
    );

    const lines: string[] = [
        `*${gameName}* ${openClose.toUpperCase()} ${formatCopyDate(date)}`,
        `Total Amount : ${formatCopyAmount(grandTotal)}`,
        '',
    ];

    for (const group of sections) {
        const sorted = sortRowsByBidNumber(group.rows);
        const total = sorted.reduce((sum, row) => sum + rowAmount(row), 0);

        lines.push(group.fname);
        lines.push(`Total Amount: ${formatCopyAmount(total)}`);
        for (const row of sorted) {
            lines.push(`${row.bid_game_number} - ${formatCopyAmount(rowAmount(row))}`);
        }
        lines.push('');
    }

    return lines.join('\n').trimEnd();
}

async function copyText(text: string) {
    try {
        await navigator.clipboard.writeText(text);
        toast.success('Copied to clipboard');
    } catch {
        toast.error('Could not copy');
    }
}

function BidTypeTable({
    copyLabel,
    gameName,
    openClose,
    rows,
    typeLabel,
    onCopy,
}: {
    copyLabel: string;
    gameName: string;
    openClose: string;
    rows: BidRow[];
    typeLabel: (name: string) => string;
    onCopy: () => void;
}) {
    const [open, setOpen] = useState(false);
    const totalAmount = rows.reduce((sum, row) => sum + (Number(row.amount) || 0), 0);

    return (
        <div className="space-y-2">
            <Button
                type="button"
                variant="outline"
                size="sm"
                className="gap-2"
                disabled={rows.length === 0}
                onClick={onCopy}
            >
                <Copy className="size-4" aria-hidden />
                Copy {copyLabel}
            </Button>

            <div className="overflow-hidden rounded-xl border border-border">
                <button
                    type="button"
                    className="flex w-full cursor-pointer items-center gap-2 bg-amber-500 px-3 py-2 text-left text-sm font-medium text-white"
                    aria-expanded={open}
                    onClick={() => setOpen((current) => !current)}
                >
                    <span className="min-w-0 flex-1 truncate">
                        {copyLabel} · Total Bet : {rows.length} , Total Amount : {totalAmount}
                    </span>
                    <ChevronDown
                        className={cn(
                            'size-4 shrink-0 transition-transform',
                            open && 'rotate-180',
                        )}
                        aria-hidden
                    />
                </button>

                {open && (
                    <div className="overflow-x-auto">
                        <table className="w-full min-w-[520px] text-center text-sm">
                            <thead>
                                <tr className="bg-amber-500/80 text-white">
                                    <th className="px-3 py-2 font-medium">Game</th>
                                    <th className="px-3 py-2 font-medium">Type</th>
                                    <th className="px-3 py-2 font-medium">Open Close</th>
                                    <th className="px-3 py-2 font-medium">No.</th>
                                    <th className="px-3 py-2 font-medium">Bet</th>
                                </tr>
                            </thead>
                            <tbody>
                                {rows.length === 0 ? (
                                    <tr>
                                        <td
                                            colSpan={5}
                                            className="px-3 py-8 text-muted-foreground"
                                        >
                                            No records found
                                        </td>
                                    </tr>
                                ) : (
                                    rows.map((row) => (
                                        <tr
                                            key={`${row.game_type}-${row.bid_game_number}`}
                                            className="border-t border-border/60"
                                        >
                                            <td className="px-3 py-2">
                                                {gameName || row.game_name}
                                            </td>
                                            <td className="px-3 py-2">
                                                {typeLabel(row.game_type)}
                                            </td>
                                            <td className="px-3 py-2">{openClose}</td>
                                            <td className="px-3 py-2">{row.bid_game_number}</td>
                                            <td className="px-3 py-2">{row.amount}</td>
                                        </tr>
                                    ))
                                )}
                            </tbody>
                        </table>
                    </div>
                )}
            </div>
        </div>
    );
}

export default function Report({
    auth,
    domains,
    games,
    gameTypes,
    filters,
    applied,
    rows,
    error,
    summary,
}: {
    auth: { user: { first_name: string; last_name: string; email: string } | null };
    domains: DomainOption[];
    games: GameOption[];
    gameTypes: GameTypeOption[];
    filters: ReportFilters;
    applied: boolean;
    rows: BidRow[];
    error: string | null;
    summary: ReportSummary;
}) {
    const [localFilters, setLocalFilters] = useState(filters);
    const [dateOpen, setDateOpen] = useState(false);
    const { collapsed: sidebarCollapsed, mobileOpen, toggleSidebar, closeMobile, showOpenIcon } =
        useAppSidebar();

    useEffect(() => {
        setLocalFilters(filters);
    }, [filters]);

    useEffect(() => {
        if (error) {
            toast.error(error);
        }
    }, [error]);

    const gameTypeLabelByName = useMemo(() => {
        const map = new Map<string, string>();
        for (const type of gameTypes) {
            map.set(type.name.toLowerCase(), type.fname);
        }
        return map;
    }, [gameTypes]);

    // Use applied (server) filters for the results panel so changing dropdowns
    // does not mutate the table until Filter is clicked.
    const appliedGameType = useMemo(
        () => gameTypes.find((type) => type.name === filters.game_type) ?? null,
        [gameTypes, filters.game_type],
    );

    function gameTypeLabel(name: string): string {
        const key = name.toLowerCase();
        return gameTypeLabelByName.get(key) ?? name;
    }

    const tablesByType = useMemo(() => {
        const byType = new Map<string, BidRow[]>();
        for (const row of rows) {
            const key = row.game_type.toLowerCase();
            const list = byType.get(key) ?? [];
            list.push(row);
            byType.set(key, list);
        }

        for (const [key, typeRows] of byType) {
            byType.set(
                key,
                [...typeRows].sort(
                    (a, b) => (Number(b.amount) || 0) - (Number(a.amount) || 0),
                ),
            );
        }

        if (appliedGameType) {
            return [
                {
                    name: appliedGameType.name,
                    fname: appliedGameType.fname,
                    rows: byType.get(appliedGameType.name.toLowerCase()) ?? [],
                },
            ];
        }

        const grouped: { name: string; fname: string; rows: BidRow[] }[] = [];
        const seen = new Set<string>();

        for (const type of gameTypes) {
            const key = type.name.toLowerCase();
            const typeRows = byType.get(key) ?? [];
            if (typeRows.length === 0) {
                continue;
            }
            grouped.push({ name: type.name, fname: type.fname, rows: typeRows });
            seen.add(key);
        }

        for (const [name, typeRows] of byType) {
            if (seen.has(name) || typeRows.length === 0) {
                continue;
            }
            grouped.push({
                name,
                fname: gameTypeLabelByName.get(name) ?? name,
                rows: typeRows,
            });
        }

        return grouped;
    }, [appliedGameType, gameTypeLabelByName, gameTypes, rows]);

    function applyFilters() {
        if (!localFilters.game_id) {
            toast.error('Please select a game');
            return;
        }
        if (!localFilters.open_close) {
            toast.error('Please select Open or Close');
            return;
        }

        visitReport({
            ...localFilters,
            domain_id: localFilters.domain_id || 'all',
            game_type: localFilters.game_type || 'all',
            filter: true,
        });
    }

    return (
        <>
            <Head title="Report" />
            <Toaster position="bottom-right" />

            <div className="flex h-svh gap-3 overflow-hidden bg-background p-3">
                <AppSidebar
                    auth={auth}
                    collapsed={sidebarCollapsed}
                    mobileOpen={mobileOpen}
                    onMobileClose={closeMobile}
                    active="report"
                />

                <div className="flex min-w-0 flex-1 flex-col gap-3 overflow-hidden">
                    <header className="flex h-12 shrink-0 items-center justify-between gap-3 rounded-2xl border border-border bg-card px-4 shadow-sm">
                        <div className="flex min-w-0 items-center gap-3">
                            <Button
                                type="button"
                                variant="ghost"
                                size="icon"
                                className="cursor-pointer"
                                aria-label={showOpenIcon ? 'Open sidebar' : 'Close sidebar'}
                                onClick={toggleSidebar}
                            >
                                {showOpenIcon ? (
                                    <PanelLeftOpen className="size-4" aria-hidden />
                                ) : (
                                    <PanelLeftClose className="size-4" aria-hidden />
                                )}
                            </Button>
                            <div className="truncate text-sm font-semibold">Report</div>
                        </div>

                        <Button
                            type="button"
                            variant="ghost"
                            size="sm"
                            className="h-8 gap-1.5 text-xs"
                            onClick={() => router.post(route('logout'))}
                        >
                            <LogOut className="size-4" aria-hidden />
                            Sign out
                        </Button>
                    </header>

                    <main className="flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto rounded-2xl border border-border bg-card p-4 shadow-sm sm:p-6">
                        <div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
                            <div>
                                <label className="mb-1.5 block text-xs font-medium text-muted-foreground">
                                    Domain
                                </label>
                                <select
                                    className={selectClassName}
                                    value={localFilters.domain_id}
                                    onChange={(e) =>
                                        setLocalFilters((prev) => ({
                                            ...prev,
                                            domain_id: e.target.value,
                                        }))
                                    }
                                >
                                    <option value="all">All</option>
                                    {domains.map((domain) => (
                                        <option key={domain.id} value={domain.id}>
                                            {domain.account_name || domain.domain}
                                        </option>
                                    ))}
                                </select>
                            </div>

                            <div>
                                <label className="mb-1.5 block text-xs font-medium text-muted-foreground">
                                    Game Type
                                </label>
                                <select
                                    className={selectClassName}
                                    value={localFilters.game_type || 'all'}
                                    onChange={(e) =>
                                        setLocalFilters((prev) => ({
                                            ...prev,
                                            game_type: e.target.value,
                                        }))
                                    }
                                >
                                    <option value="all">All</option>
                                    {gameTypes.map((type) => (
                                        <option key={type.name} value={type.name}>
                                            {type.fname}
                                        </option>
                                    ))}
                                </select>
                            </div>

                            <div>
                                <label className="mb-1.5 block text-xs font-medium text-muted-foreground">
                                    Game
                                </label>
                                <select
                                    className={selectClassName}
                                    value={localFilters.game_id}
                                    onChange={(e) =>
                                        setLocalFilters((prev) => ({
                                            ...prev,
                                            game_id: e.target.value,
                                        }))
                                    }
                                >
                                    <option value="">Select game</option>
                                    {games.map((game) => (
                                        <option key={game.id} value={game.id}>
                                            {game.game_name}
                                        </option>
                                    ))}
                                </select>
                            </div>

                            <div>
                                <label className="mb-1.5 block text-xs font-medium text-muted-foreground">
                                    Date
                                </label>
                                <Popover open={dateOpen} onOpenChange={setDateOpen}>
                                    <PopoverTrigger
                                        render={
                                            <Button
                                                type="button"
                                                variant="outline"
                                                className="h-9 w-full justify-start gap-2 px-3 text-sm font-normal"
                                            />
                                        }
                                    >
                                        <CalendarIcon className="size-4 shrink-0 opacity-60" />
                                        {localFilters.date
                                            ? formatDisplayDate(localFilters.date)
                                            : 'Pick a date'}
                                    </PopoverTrigger>
                                    <PopoverContent align="start" className="w-auto p-0">
                                        <Calendar
                                            mode="single"
                                            selected={
                                                localFilters.date
                                                    ? parseLocalDate(localFilters.date)
                                                    : undefined
                                            }
                                            disabled={{ after: todayDate() }}
                                            onSelect={(date) => {
                                                if (!date) {
                                                    return;
                                                }
                                                setLocalFilters((prev) => ({
                                                    ...prev,
                                                    date: toIsoDate(date),
                                                }));
                                                setDateOpen(false);
                                            }}
                                        />
                                    </PopoverContent>
                                </Popover>
                            </div>

                            <div>
                                <label className="mb-1.5 block text-xs font-medium text-muted-foreground">
                                    Open / Close
                                </label>
                                <select
                                    className={selectClassName}
                                    value={localFilters.open_close}
                                    onChange={(e) =>
                                        setLocalFilters((prev) => ({
                                            ...prev,
                                            open_close: e.target.value,
                                        }))
                                    }
                                >
                                    <option value="">Select market</option>
                                    <option value="open">Open</option>
                                    <option value="close">Close</option>
                                </select>
                            </div>

                            <div className="flex flex-col justify-end">
                                <span className="mb-1.5 block text-xs font-medium text-transparent select-none">
                                    Filter
                                </span>
                                <Button
                                    type="button"
                                    className="h-9 w-full cursor-pointer"
                                    onClick={applyFilters}
                                >
                                    Filter
                                </Button>
                            </div>
                        </div>

                        {applied && (
                            <>
                                <div className="flex flex-col gap-2 rounded-xl bg-amber-500 px-4 py-3 text-sm font-medium text-white sm:flex-row sm:items-center sm:justify-between">
                                    <span>
                                        {summary.game_name} ({summary.open_close})
                                    </span>
                                    <span>{formatDisplayDate(summary.date)}</span>
                                </div>

                                <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
                                    <Button
                                        type="button"
                                        variant="outline"
                                        size="sm"
                                        className="gap-2"
                                        disabled={rows.length === 0}
                                        onClick={() =>
                                            copyText(
                                                buildAllBidsCopyText(
                                                    summary.game_name,
                                                    summary.open_close,
                                                    summary.date,
                                                    tablesByType,
                                                ),
                                            )
                                        }
                                    >
                                        <Copy className="size-4" aria-hidden />
                                        Copy All Bids
                                    </Button>

                                    <div className="rounded-full bg-amber-500 px-4 py-2 text-sm font-medium text-white">
                                        Total Bet : {summary.total_bet} , Total Amount :{' '}
                                        {summary.total_amount}
                                    </div>
                                </div>

                                {tablesByType.length === 0 ? (
                                    <p className="py-8 text-center text-sm text-muted-foreground">
                                        No records found
                                    </p>
                                ) : (
                                    <div className="space-y-3">
                                        {tablesByType.map((group) => (
                                            <BidTypeTable
                                                key={`${filters.game_id}-${filters.date}-${filters.open_close}-${filters.game_type}-${group.name}`}
                                                copyLabel={group.fname}
                                                gameName={summary.game_name}
                                                openClose={summary.open_close}
                                                rows={group.rows}
                                                typeLabel={gameTypeLabel}
                                                onCopy={() =>
                                                    copyText(
                                                        buildCopyText(
                                                            group.fname,
                                                            summary.game_name,
                                                            summary.open_close,
                                                            summary.date,
                                                            group.rows,
                                                        ),
                                                    )
                                                }
                                            />
                                        ))}
                                    </div>
                                )}
                            </>
                        )}

                        {!applied && (
                            <p className="text-sm text-muted-foreground">
                                Select domain, game type, game, date, and open/close, then click
                                Filter. Choose All for game type to load bids for every type.
                            </p>
                        )}
                    </main>
                </div>
            </div>
        </>
    );
}
