import { Activity, RefreshCw, ShieldCheck } from "lucide-react";
import { useCallback, useEffect, useRef, useState } from "react";
import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { DataCardState } from "./DataCardState";
import type { MarketType } from "@/lib/market";
import type {
    SignalCalibrationMeta,
    SignalSetup,
    SignalWalkForwardResult,
    SignalMode,
} from "@/types/insight";
import { SignalSnapshot } from "@/lib/SignalSnapshot";

type Props = {
    symbol: string;
    market: MarketType;
    interval: string;
    provider: string;
    signal: SignalSetup | null;
    enabled: boolean;
    signalMode?: SignalMode;
    loading?: boolean;
    signalSnapshot?: SignalSnapshot | null;
};

type CurrentResponse = {
    active: boolean;
    calibration: {
        sample_size: number;
        train_start: string | null;
        train_end: string | null;
        version: string;
        metrics: NonNullable<SignalCalibrationMeta["metrics"]>;
    } | null;
};

type WalkForwardResponse = {
    out_of_sample?: SignalWalkForwardResult;
};

const pct = (value: number | null | undefined) =>
    value == null ? "—" : `${value.toFixed(1)}%`;

export default function SignalCalibrationPanel({
    symbol,
    market,
    interval,
    provider,
    signal,
    enabled,
    signalMode = "strict",
    loading: externalLoading = false,
}: Props) {
    const [current, setCurrent] = useState<CurrentResponse | null>(null);
    const [walkForward, setWalkForward] =
        useState<SignalWalkForwardResult | null>(null);
    const [loading, setLoading] = useState(false);
    const [runningWalkForward, setRunningWalkForward] = useState(false);
    const [error, setError] = useState<string | null>(null);
    const requestIdRef = useRef(0);
    const activeRequestRef = useRef<{
        key: string;
        controller: AbortController;
    } | null>(null);

    const load = useCallback(async () => {
        if (!enabled) return;
        const params = new URLSearchParams({
            symbol,
            market,
            interval,
            provider,
            signal_mode: signalMode,
            direction:
                signal?.direction === "short"
                    ? "short"
                    : signal?.direction === "long"
                      ? "long"
                      : "both",
        });
        const requestKey = params.toString();

        // The same effect may be replayed by StrictMode in development. Reuse
        // an identical in-flight request, but supersede it when its parameters
        // change so stale calibration data cannot overwrite the new context.
        if (activeRequestRef.current?.key === requestKey) return;
        activeRequestRef.current?.controller.abort();

        const requestId = ++requestIdRef.current;
        const controller = new AbortController();
        activeRequestRef.current = { key: requestKey, controller };
        setLoading(true);
        setError(null);
        try {
            const response = await fetch(
                `/market/signals/calibration?${params.toString()}`,
                {
                    headers: {
                        Accept: "application/json",
                        "X-Requested-With": "XMLHttpRequest",
                    },
                    credentials: "same-origin",
                    cache: "no-store",
                    signal: controller.signal,
                },
            );
            const raw: unknown = await response.json();
            if (!response.ok)
                throw new Error(
                    raw &&
                        typeof raw === "object" &&
                        "message" in raw &&
                        typeof raw.message === "string"
                        ? raw.message
                        : "Gagal mengambil calibration.",
                );
            if (requestId !== requestIdRef.current) return;
            setCurrent(raw as CurrentResponse);
        } catch (e) {
            if (requestId !== requestIdRef.current) return;
            if (e instanceof Error && e.name === "AbortError") return;
            setError(
                e instanceof Error ? e.message : "Gagal mengambil calibration.",
            );
        } finally {
            if (requestId === requestIdRef.current) {
                activeRequestRef.current = null;
                setLoading(false);
            }
        }
    }, [
        enabled,
        signalMode,
        interval,
        market,
        signal?.direction,
        signal?.signal_mode,
        symbol,
    ]);

    const runWalkForward = async () => {
        setRunningWalkForward(true);
        setError(null);
        try {
            const end = new Date();
            const start = new Date(end.getTime() - 120 * 24 * 60 * 60 * 1000);
            const body = {
                symbol,
                market,
                interval,
                signal_mode: signalMode,
                direction:
                    signal?.direction === "short"
                        ? "short"
                        : signal?.direction === "long"
                          ? "long"
                          : "both",
                start_date: start.toISOString().slice(0, 10),
                end_date: end.toISOString().slice(0, 10),
                folds: 3,
                candles_limit: 500,
                max_trades: 100,
                fee_pct: 0.1,
                slippage_pct: 0.05,
                ambiguity: "conservative",
            };
            const response = await fetch("/market/signals/walk-forward", {
                method: "POST",
                headers: {
                    Accept: "application/json",
                    "Content-Type": "application/json",
                    "X-Requested-With": "XMLHttpRequest",
                },
                credentials: "same-origin",
                body: JSON.stringify(body),
            });
            const raw: unknown = await response.json();
            if (!response.ok)
                throw new Error(
                    raw &&
                        typeof raw === "object" &&
                        "message" in raw &&
                        typeof raw.message === "string"
                        ? raw.message
                        : "Walk-forward gagal dijalankan.",
                );
            setWalkForward((raw as WalkForwardResponse).out_of_sample ?? null);
        } catch (e) {
            setError(
                e instanceof Error
                    ? e.message
                    : "Walk-forward gagal dijalankan.",
            );
        } finally {
            setRunningWalkForward(false);
        }
    };

    useEffect(() => {
        void load();
    }, [load]);

    if (!enabled) return null;

    const calibration = current?.calibration;
    const meta = signal?.calibration;
    const metrics = calibration?.metrics;
    const sampleSize = meta?.sample_size || calibration?.sample_size || 0;

    return (
        <Card className="mt-0 border-border bg-card/80 shadow-xs py-3 px-0!">
            <CardHeader className="flex flex-col gap-2.5 border-b border-border/60 py-3 sm:flex-row sm:items-center sm:justify-between">
                <div className="flex items-center gap-3">
                    <div className="flex h-10 w-10 items-center justify-center rounded-xl border border-border bg-muted/40 text-primary">
                        <ShieldCheck className="size-5" />
                    </div>
                    <div>
                        <div className="text-[11px] font-semibold uppercase tracking-[.14em] text-muted-foreground">
                            Signal Calibration
                        </div>
                        <div className="mt-0.5 flex items-center gap-2 text-sm font-semibold">
                            Probability calibration & out-of-sample validation
                            <span className="rounded-md border border-border px-1.5 py-0.5 text-[9px] uppercase tracking-wide text-muted-foreground">
                                {signalMode === "balanced"
                                    ? "Balanced"
                                    : signalMode === "flexible"
                                      ? "Flexible"
                                      : "Strict"}
                            </span>
                        </div>
                    </div>
                </div>
                <Button
                    type="button"
                    variant="outline"
                    size="sm"
                    onClick={() => void load()}
                    disabled={loading || externalLoading}
                    className="h-9 gap-2"
                >
                    <RefreshCw
                        className={`size-3.5 ${loading || externalLoading ? "animate-spin" : ""}`}
                    />{" "}
                    Refresh
                </Button>
            </CardHeader>
            <CardContent className="pt-3">
                {externalLoading ? (
                    <div
                        className="space-y-4"
                        role="status"
                        aria-label="Loading signal calibration"
                    >
                        <div className="grid grid-cols-2 gap-2 md:grid-cols-5">
                            {Array.from({ length: 5 }).map((_, index) => (
                                <div
                                    key={index}
                                    className="h-16 animate-pulse rounded-lg bg-muted"
                                />
                            ))}
                        </div>
                        <div className="h-12 animate-pulse rounded-lg bg-muted" />
                    </div>
                ) : (
                    <>
                        <DataCardState
                            loading={loading}
                            error={error}
                            hasData={Boolean(current || meta || signal)}
                            onRetry={() => void load()}
                            loadingLabel="Loading signal calibration…"
                            empty={
                                !loading &&
                                !error &&
                                !current &&
                                !meta &&
                                !signal
                            }
                            emptyLabel="Calibration belum tersedia karena belum ada signal yang dapat divalidasi untuk mode ini."
                        />
                        <div className="grid grid-cols-2 gap-2 md:grid-cols-5">
                            <Metric
                                label="Raw confidence"
                                value={`${signal?.raw_confidence ?? meta?.raw ?? "—"}%`}
                            />
                            <Metric
                                label="Calibrated probability"
                                value={pct(
                                    meta?.probability_pct ??
                                        signal?.confidence ??
                                        null,
                                )}
                            />
                            <Metric
                                label="Sample size"
                                value={
                                    sampleSize
                                        ? sampleSize.toLocaleString()
                                        : "—"
                                }
                            />
                            <Metric
                                label="Calibration error (ECE)"
                                value={pct(metrics?.expected_calibration_error)}
                            />
                            <Metric
                                label="Observed positive"
                                value={pct(metrics?.actual_positive_rate)}
                            />
                        </div>

                        <div className="mt-3 flex flex-col gap-2.5 rounded-lg border border-border/60 bg-muted/20 p-2.5 text-xs md:flex-row md:items-center md:justify-between">
                            <div className="flex items-center gap-2 text-muted-foreground">
                                <Activity className="size-4" />
                                {current?.active
                                    ? `Calibration aktif · ${sampleSize.toLocaleString()} outcomes`
                                    : "Belum ada calibration aktif untuk kombinasi ini."}
                            </div>
                            <Button
                                type="button"
                                size="sm"
                                variant="secondary"
                                onClick={runWalkForward}
                                disabled={runningWalkForward}
                                className="gap-2"
                            >
                                <Activity
                                    className={`size-3.5 ${runningWalkForward ? "animate-pulse" : ""}`}
                                />
                                {runningWalkForward
                                    ? "Running…"
                                    : "Run walk-forward (120d)"}
                            </Button>
                        </div>

                        {walkForward && (
                            <div className="mt-2 grid grid-cols-3 gap-2 rounded-lg border border-border/60 p-2.5">
                                <Metric
                                    label="OOS samples"
                                    value={walkForward.samples.toLocaleString()}
                                />
                                <Metric
                                    label="OOS Brier score"
                                    value={
                                        walkForward.brier_score == null
                                            ? "—"
                                            : walkForward.brier_score.toFixed(4)
                                    }
                                />
                                <Metric
                                    label="OOS positive rate"
                                    value={pct(
                                        walkForward.actual_positive_rate,
                                    )}
                                />
                            </div>
                        )}

                        <p className="mt-2.5 text-[11px] leading-relaxed text-muted-foreground">
                            Probability adalah estimasi historis, bukan jaminan
                            hasil. ECE/Brier dan walk-forward harus dibaca
                            bersama sample size, biaya, slippage, dan regime
                            pasar.
                        </p>
                    </>
                )}
            </CardContent>
        </Card>
    );
}

function Metric({ label, value }: { label: string; value: string }) {
    return (
        <div className="rounded-lg border border-border/60 bg-background/60 p-2.5">
            <div className="text-[10px] font-medium uppercase tracking-wide text-muted-foreground">
                {label}
            </div>
            <div className="mt-1 text-sm font-semibold tabular-nums">
                {value}
            </div>
        </div>
    );
}
