import { Head, Link } from "@inertiajs/react";
import {
    ReactNode,
    useCallback,
    useEffect,
    useMemo,
    useRef,
    useState,
} from "react";
import {
    Activity,
    AlertTriangle,
    ArrowDownRight,
    ArrowUpRight,
    CheckCircle2,
    Clock3,
    ExternalLink,
    Filter,
    LoaderCircle,
    Play,
    Radar,
    RefreshCw,
    Search,
    ShieldAlert,
    ShieldCheck,
    Square,
    TrendingUp,
    XCircle,
    Zap,
} from "lucide-react";

import { useI18n } from "@/lib/i18n";
import CustomerWorkspaceNav from "@/components/customer-workspace-nav";
import ScannerDiscoverySummary from "@/components/scanner-discovery-summary";
// Import komponen Shadcn UI
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
    Card,
    CardContent,
    CardDescription,
    CardHeader,
    CardTitle,
} from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import {
    Collapsible,
    CollapsibleContent,
    CollapsibleTrigger,
} from "@/components/ui/collapsible";
import { Label } from "@/components/ui/label";
import {
    Select,
    SelectContent,
    SelectItem,
    SelectTrigger,
    SelectValue,
} from "@/components/ui/select";
import {
    Table,
    TableBody,
    TableCell,
    TableHead,
    TableHeader,
    TableRow,
} from "@/components/ui/table";
import AppLayout from "@/layouts/app-layout";

type Market = "spot" | "futures";
type SignalMode = "strict" | "balanced" | "flexible";
type ScanUniverse = "watchlist" | "market";
type ResultState = "confirmed" | "candidate" | "blocked" | "error";
type ScanStatus = "idle" | "scanning" | "completed" | "stopped";
type ConfidenceFilter = "all" | "10" | "20" | "50";
type JsonRecord = Record<string, unknown>;

type GateDetail = {
    key: string;
    label: string;
    status: "pass" | "block" | "warn";
    severity: "hard" | "soft";
    stage: "candidate" | "execution";
    value: unknown;
    target: unknown;
};

type WatchlistItem = {
    symbol: string;
    market: Market;
};

type ProviderOption = {
    name: string;
    slug: string;
    markets: Market[];
};

type ScanResult = {
    symbol: string;
    market: Market;
    provider: string;
    interval: string;
    signalMode: SignalMode;
    state: ResultState;
    action: "LONG" | "SHORT" | "BUY" | "SELL" | "—";
    score: number | null;
    confidence: number | null;
    price: number | null;
    entry: number | null;
    stopLoss: number | null;
    takeProfit: number | null;
    riskReward: number | null;
    candleTime: number | null;
    candidateEligible: boolean;
    gateDetails: GateDetail[];
    reasons: string[];
    message: string;
};

type ScanProgress = {
    total: number;
    completed: number;
    currentSymbol: string | null;
};

const INTERVALS = ["5m", "15m", "30m", "1h", "4h", "1d"];
const MODE_OPTIONS: {
    value: SignalMode;
    label: string;
    description: string;
}[] = [
    {
        value: "strict",
        label: "Strict",
        description:
            "Most selective analytical confirmation; all required evidence checks must align before a result is surfaced as strong.",
    },
    {
        value: "balanced",
        label: "Balanced",
        description:
            "Core evidence is required; supporting evidence is more flexible while quality checks remain mandatory.",
    },
    {
        value: "flexible",
        label: "Flexible",
        description:
            "Surface earlier research candidates; multi-timeframe, trigger, context, and data-quality checks still apply.",
    },
];

const REQUEST_SPACING_MS = 1_200;
const CONFIDENCE_FILTER_OPTIONS: { value: ConfidenceFilter; label: string }[] =
    [
        { value: "all", label: "All" },
        { value: "10", label: "Above 10%" },
        { value: "20", label: "Above 20%" },
        { value: "50", label: "Above 50%" },
    ];
const SCAN_LIMIT_OPTIONS = [
    { value: "all", label: "All" },
    { value: "250", label: "250 coins" },
    { value: "100", label: "100 coins" },
    { value: "50", label: "50 coins" },
    { value: "25", label: "25 coins" },
] as const;

function asRecord(value: unknown): JsonRecord {
    return value !== null && typeof value === "object" && !Array.isArray(value)
        ? (value as JsonRecord)
        : {};
}

function asRecordList(value: unknown): JsonRecord[] {
    return Array.isArray(value) ? value.map(asRecord) : [];
}

function finiteNumber(value: unknown): number | null {
    if (typeof value !== "number" && typeof value !== "string") return null;
    if (typeof value === "string" && value.trim() === "") return null;
    const number = Number(value);
    return Number.isFinite(number) ? number : null;
}

function stringList(value: unknown): string[] {
    if (!Array.isArray(value)) return [];
    return value.filter((item): item is string => typeof item === "string");
}

function formatPrice(value: number | null): string {
    if (value === null || value <= 0) return "—";
    return value.toLocaleString(undefined, { maximumFractionDigits: 8 });
}

function formatScore(value: number | null): string {
    if (value === null) return "—";
    return `${value > 0 ? "+" : ""}${value.toFixed(1)}`;
}

function formatPercent(value: number | null): string {
    return value === null ? "—" : `${Math.round(value)}%`;
}

function hasPositiveConfidence(item: ScanResult): boolean {
    return (
        item.confidence !== null &&
        Number.isFinite(item.confidence) &&
        item.confidence > 0
    );
}

function matchesConfidenceFilter(
    item: ScanResult,
    filter: ConfidenceFilter,
): boolean {
    if (item.state === "error") return true;
    if (!hasPositiveConfidence(item)) return false;
    return filter === "all" || item.confidence! > Number(filter);
}

function formatRatio(value: number | null): string {
    return value === null ? "—" : `${value.toFixed(2)}R`;
}

function formatDate(value: number | null): string {
    if (value === null || value <= 0) return "—";
    return new Date(value * 1000).toLocaleTimeString([], {
        hour: "2-digit",
        minute: "2-digit",
        second: "2-digit",
    });
}

function directionLabel(action: ScanResult["action"], translate: ReturnType<typeof useI18n>["t"]): string {
    if (action === "LONG" || action === "BUY") return translate("Bullish");
    if (action === "SHORT" || action === "SELL") return translate("Bearish");
    return translate("Neutral");
}

function directionIcon(action: ScanResult["action"]) {
    if (action === "LONG" || action === "BUY") return ArrowUpRight;
    if (action === "SHORT" || action === "SELL") return ArrowDownRight;
    return Activity;
}

function formatGateValue(value: unknown): string {
    if (value === null || value === undefined || value === "") return "—";
    if (typeof value === "boolean") return value ? "Yes" : "No";
    if (typeof value === "string" || typeof value === "number")
        return String(value);

    try {
        const serialized = JSON.stringify(value);
        return serialized.length > 120
            ? `${serialized.slice(0, 117)}…`
            : serialized;
    } catch {
        return "—";
    }
}

async function requestJson(
    url: string,
    signal?: AbortSignal,
): Promise<unknown> {
    const response = await fetch(url, {
        headers: { Accept: "application/json" },
        credentials: "same-origin",
        cache: "no-store",
        signal,
    });

    let payload: unknown = null;
    try {
        payload = await response.json();
    } catch {
        payload = null;
    }

    if (!response.ok) {
        const message = asRecord(payload).message;
        throw new Error(
            typeof message === "string"
                ? message
                : `Permintaan gagal (HTTP ${response.status}).`,
        );
    }

    return payload;
}

function parseAnalysis(
    rawValue: unknown,
    item: WatchlistItem,
    provider: string,
    interval: string,
    signalMode: SignalMode,
): ScanResult {
    const { t } = useI18n();
    const raw = asRecord(rawValue);
    const responseContext = {
        symbol: String(raw.symbol ?? "")
            .trim()
            .toUpperCase(),
        market: String(raw.market ?? "")
            .trim()
            .toLowerCase(),
        provider: String(raw.provider ?? "")
            .trim()
            .toLowerCase(),
        interval: String(asRecord(raw.primary).interval ?? "")
            .trim()
            .toLowerCase(),
        signalMode: String(raw.signal_mode ?? "")
            .trim()
            .toLowerCase(),
    };
    const expectedProvider = provider.trim().toLowerCase() || "binance";
    // Fail closed if an API/cache response belongs to a different analysis
    // context. Never relabel mismatched server data as the requested symbol,
    // market, provider, interval, or signal mode in the scanner UI.
    if (
        responseContext.symbol !== item.symbol.trim().toUpperCase() ||
        responseContext.market !== item.market ||
        responseContext.provider !== expectedProvider ||
        responseContext.interval !== interval.trim().toLowerCase() ||
        responseContext.signalMode !== signalMode
    ) {
        return errorResult(
            item,
            expectedProvider,
            interval,
            signalMode,
            "The analysis response context does not match the request. The result is withheld to prevent status or price levels from another analysis from being displayed.",
        );
    }

    const setup = asRecord(raw.setup);
    const policy = asRecord(raw.policy ?? setup.policy);
    const plan = asRecord(setup.trade_plan);
    const primary = asRecord(raw.primary);
    const spot = asRecord(raw.spot);
    const riskRewardObject = asRecord(setup.risk_reward);

    const score =
        finiteNumber(primary.adaptive_score) ??
        finiteNumber(primary.score) ??
        finiteNumber(asRecord(raw.overall).score);
    const confidence = finiteNumber(setup.confidence);
    const price = finiteNumber(raw.price);
    const entry = finiteNumber(setup.entry);
    const stopLoss = finiteNumber(setup.sl);
    const takeProfit = finiteNumber(setup.tp);
    const riskReward =
        finiteNumber(riskRewardObject.ratio) ??
        finiteNumber(plan.risk_reward) ??
        finiteNumber(setup.risk_reward);
    const candleTime =
        finiteNumber(primary.candle_time) ?? finiteNumber(setup.time);

    const candidateDirection = String(
        setup.candidate_direction ?? setup.direction ?? "neutral",
    ).toLowerCase();
    const spotAction = String(
        spot.action ?? setup.candidate_action ?? setup.action ?? "neutral",
    ).toLowerCase();
    const action: ScanResult["action"] =
        item.market === "spot"
            ? spotAction === "buy"
                ? "BUY"
                : spotAction === "sell"
                  ? "SELL"
                  : candidateDirection === "long"
                    ? "BUY"
                    : candidateDirection === "short"
                      ? "SELL"
                      : "—"
            : candidateDirection === "long"
              ? "LONG"
              : candidateDirection === "short"
                ? "SHORT"
                : "—";

    const levelsHaveValidGeometry =
        entry !== null &&
        stopLoss !== null &&
        takeProfit !== null &&
        entry > 0 &&
        stopLoss > 0 &&
        takeProfit > 0 &&
        ((candidateDirection === "long" &&
            stopLoss < entry &&
            entry < takeProfit) ||
            (candidateDirection === "short" &&
                takeProfit < entry &&
                entry < stopLoss));
    const policyEligible = policy.eligible === true;
    const candidateEligible =
        policy.candidate_eligible === true ||
        (policy.candidate_eligible === undefined && policyEligible);
    const executionAllowed =
        policy.execution_allowed === true && setup.execution_allowed === true;
    const planValid = plan.valid === true && levelsHaveValidGeometry;
    const isSpotSell = item.market === "spot" && action === "SELL";
    const confirmed =
        policyEligible &&
        executionAllowed &&
        planValid &&
        action !== "—" &&
        !isSpotSell &&
        (item.market === "spot"
            ? action === "BUY" && candidateDirection === "long"
            : (action === "LONG" && candidateDirection === "long") ||
              (action === "SHORT" && candidateDirection === "short"));

    const hardFailures = stringList(policy.hard_failures);
    const candidateFailures = stringList(policy.candidate_failures);
    const executionBlockers = stringList(policy.execution_blockers);
    const warnings = stringList(policy.warnings);
    const gateDetails = asRecordList(policy.decision_trace)
        .map(
            (gate): GateDetail => ({
                key: String(gate.key ?? ""),
                label: String(gate.label ?? gate.key ?? "Check"),
                status:
                    gate.status === "pass" || gate.status === "warn"
                        ? gate.status
                        : "block",
                severity: gate.severity === "soft" ? "soft" : "hard",
                stage: gate.stage === "execution" ? "execution" : "candidate",
                value: gate.value,
                target: gate.target,
            }),
        )
        .filter((gate) => gate.key !== "");
    const reasons = [
        ...candidateFailures,
        ...executionBlockers.map((reason) =>
            t("Entry held: :reason", "Entry held: :reason", { reason }),
        ),
        ...hardFailures,
        ...warnings,
        ...stringList(setup.reason),
    ]
        .filter(
            (reason, index, list) =>
                reason.trim() !== "" && list.indexOf(reason) === index,
        )
        .slice(0, 6);

    let state: ResultState = "blocked";
    let message = t("Not all confirmation requirements are met.");
    if (confirmed) {
        state = "confirmed";
        message = t(
            "Passed the analysis policy, evidence checks, and risk-context validation.",
        );
    } else if (isSpotSell) {
        state = "candidate";
        message = t(
            "Bearish spot readings are informational and should be investigated in context.",
        );
    } else if (candidateEligible) {
        state = "candidate";
        message =
            executionBlockers.length > 0
                ? t(
                      "Candidate needs further evidence before a conclusion: :reasons.",
                      "Candidate needs further evidence before a conclusion: :reasons.",
                      { reasons: executionBlockers.slice(0, 2).join("; ") },
                  )
                : "Candidate meets the current monitoring criteria.";
    } else if (action === "—") {
        state = "blocked";
        message = t("No direction meets the signal threshold.");
    } else if (hardFailures.length > 0) {
        state = "blocked";
        message = candidateFailures[0] ?? hardFailures[0];
    }

    return {
        symbol: item.symbol,
        market: item.market,
        provider,
        interval,
        signalMode,
        state,
        action,
        score,
        confidence,
        price,
        entry: confirmed ? entry : null,
        stopLoss: confirmed ? stopLoss : null,
        takeProfit: confirmed ? takeProfit : null,
        riskReward: confirmed ? riskReward : null,
        candleTime,
        candidateEligible,
        gateDetails,
        reasons,
        message,
    };
}

function errorResult(
    item: WatchlistItem,
    provider: string,
    interval: string,
    signalMode: SignalMode,
    message: string,
): ScanResult {
    return {
        symbol: item.symbol,
        market: item.market,
        provider,
        interval,
        signalMode,
        state: "error",
        action: "—",
        score: null,
        confidence: null,
        price: null,
        entry: null,
        stopLoss: null,
        takeProfit: null,
        riskReward: null,
        candleTime: null,
        candidateEligible: false,
        gateDetails: [],
        reasons: [],
        message,
    };
}

function stateLabel(state: ResultState): string {
    return {
        confirmed: "Strong match",
        candidate: "Needs review",
        blocked: "Blocked",
        error: "Analysis Error",
    }[state];
}

export default function MarketScanner() {
    const { t } = useI18n();
    const [market, setMarket] = useState<Market>("futures");
    const [universe, setUniverse] = useState<ScanUniverse>("market");
    const [scanLimit, setScanLimit] =
        useState<(typeof SCAN_LIMIT_OPTIONS)[number]["value"]>("all");
    const [signalMode, setSignalMode] = useState<SignalMode>("strict");
    const [interval, setInterval] = useState("15m");
    const [provider, setProvider] = useState("binance");
    const [watchlist, setWatchlist] = useState<WatchlistItem[]>([]);
    const [watchlistLoaded, setWatchlistLoaded] = useState(false);
    const [watchlistError, setWatchlistError] = useState("");
    const [marketCatalog, setMarketCatalog] = useState<WatchlistItem[]>([]);
    const [catalogContext, setCatalogContext] = useState("");
    const [catalogLoading, setCatalogLoading] = useState(false);
    const [catalogError, setCatalogError] = useState("");
    const [catalogReloadVersion, setCatalogReloadVersion] = useState(0);
    const [providers, setProviders] = useState<ProviderOption[]>([]);
    const [sourcesLoading, setSourcesLoading] = useState(true);
    const [sourceError, setSourceError] = useState("");
    const [scanStatus, setScanStatus] = useState<ScanStatus>("idle");
    const [progress, setProgress] = useState<ScanProgress>({
        total: 0,
        completed: 0,
        currentSymbol: null,
    });
    const [results, setResults] = useState<ScanResult[]>([]);
    const [lastScanContext, setLastScanContext] = useState("");
    const [search, setSearch] = useState("");
    const [resultFilter, setResultFilter] = useState<"all" | ResultState>(
        "all",
    );
    const [confidenceFilter, setConfidenceFilter] =
        useState<ConfidenceFilter>("all");
    const scanControllerRef = useRef<AbortController | null>(null);

    const supportedProviders = useMemo(
        () => providers.filter((item) => item.markets.includes(market)),
        [providers, market],
    );
    const selectedProvider = supportedProviders.some(
        (item) => item.slug === provider,
    )
        ? provider
        : (supportedProviders[0]?.slug ?? provider);
    const selectedWatchlist = useMemo(
        () =>
            watchlist
                .filter((item) => item.market === market)
                .filter(
                    (item, index, all) =>
                        all.findIndex(
                            (candidate) =>
                                candidate.market === item.market &&
                                candidate.symbol === item.symbol,
                        ) === index,
                ),
        [watchlist, market],
    );
    const catalogKey = `${market}|${selectedProvider}`;
    const selectedMarketCatalog = useMemo(
        () =>
            catalogContext === catalogKey
                ? marketCatalog.filter((item) => item.market === market)
                : [],
        [marketCatalog, market, catalogContext, catalogKey],
    );
    const selectedUniverse =
        universe === "watchlist" ? selectedWatchlist : selectedMarketCatalog;
    const scanItems = useMemo(
        () =>
            selectedUniverse.slice(
                0,
                scanLimit === "all"
                    ? selectedUniverse.length
                    : Number(scanLimit),
            ),
        [selectedUniverse, scanLimit],
    );
    const scanContext = `${market}|${selectedProvider}|${interval}|${signalMode}|${universe}|${scanLimit}`;
    const resultsAreStale =
        results.length > 0 && lastScanContext !== scanContext;
    const progressPercent = progress.total
        ? Math.min(100, Math.round((progress.completed / progress.total) * 100))
        : 0;
    const minimumDelaySeconds =
        (Math.max(0, scanItems.length - 1) * REQUEST_SPACING_MS) / 1000;
    const minimumDelayLabel =
        minimumDelaySeconds < 60
            ? `${Math.ceil(minimumDelaySeconds)} detik`
            : `${(minimumDelaySeconds / 60).toFixed(1)} menit`;

    const counts = useMemo(
        () => ({
            confirmed: results.filter(
                (item) =>
                    matchesConfidenceFilter(item, confidenceFilter) &&
                    item.state === "confirmed",
            ).length,
            candidate: results.filter(
                (item) =>
                    matchesConfidenceFilter(item, confidenceFilter) &&
                    item.state === "candidate",
            ).length,
            blocked: results.filter(
                (item) =>
                    matchesConfidenceFilter(item, confidenceFilter) &&
                    item.state === "blocked",
            ).length,
            error: results.filter((item) => item.state === "error").length,
        }),
        [results, confidenceFilter],
    );

    const averageConfidence = useMemo(() => {
        const values = results
            .map((item) => item.confidence)
            .filter((value): value is number => value !== null && Number.isFinite(value));
        return values.length > 0
            ? values.reduce((sum, value) => sum + value, 0) / values.length
            : null;
    }, [results]);

    const visibleResults = useMemo(() => {
        const term = search.trim().toUpperCase();
        return [...results]
            .filter((item) => matchesConfidenceFilter(item, confidenceFilter))
            .filter(
                (item) => resultFilter === "all" || item.state === resultFilter,
            )
            .filter((item) => term === "" || item.symbol.includes(term))
            .sort((a, b) => {
                const rank: Record<ResultState, number> = {
                    confirmed: 0,
                    candidate: 1,
                    blocked: 2,
                    error: 3,
                };
                return (
                    rank[a.state] - rank[b.state] ||
                    Math.abs(b.score ?? 0) - Math.abs(a.score ?? 0) ||
                    a.symbol.localeCompare(b.symbol)
                );
            });
    }, [results, resultFilter, search, confidenceFilter]);

    useEffect(() => {
        const controller = new AbortController();
        const timer = window.setTimeout(() => {
            void requestJson("/market/providers", controller.signal)
                .then((payload) => {
                    if (controller.signal.aborted) return;
                    const items = asRecordList(payload)
                        .map((item) => {
                            const markets = Array.isArray(item.markets)
                                ? item.markets
                                      .map((value) =>
                                          String(value).toLowerCase(),
                                      )
                                      .filter(
                                          (value): value is Market =>
                                              value === "spot" ||
                                              value === "futures",
                                      )
                                : [];

                            return {
                                name: String(
                                    item.name ?? item.slug ?? "Provider",
                                ),
                                slug: String(item.slug ?? "").toLowerCase(),
                                markets,
                            };
                        })
                        .filter(
                            (item) =>
                                /^[a-z0-9_-]{1,64}$/.test(item.slug) &&
                                item.markets.length > 0,
                        );
                    setProviders(items);
                    setProvider((current) =>
                        items.some((item) => item.slug === current)
                            ? current
                            : (items[0]?.slug ?? "binance"),
                    );
                    setSourceError("");
                })
                .catch((error: unknown) => {
                    if (
                        controller.signal.aborted ||
                        (error instanceof DOMException &&
                            error.name === "AbortError")
                    )
                        return;
                    setSourceError(
                        error instanceof Error
                            ? error.message
                            : t("Provider list could not be loaded."),
                    );
                })
                .finally(() => {
                    if (!controller.signal.aborted) setSourcesLoading(false);
                });
        }, 0);

        return () => {
            window.clearTimeout(timer);
            controller.abort();
        };
    }, []);

    useEffect(() => {
        if (universe !== "watchlist" || watchlistLoaded) return;

        const controller = new AbortController();
        let active = true;
        const timer = window.setTimeout(() => {
            setWatchlistError("");
            void requestJson("/user/watchlist", controller.signal)
                .then((payload) => {
                    if (!active || controller.signal.aborted) return;
                    const items = asRecordList(payload)
                        .map((item) => ({
                            symbol: String(item.symbol ?? "")
                                .toUpperCase()
                                .replace(/[\s/_-]+/g, ""),
                            market: String(item.market ?? "").toLowerCase(),
                        }))
                        .filter(
                            (item): item is WatchlistItem =>
                                /^[A-Z0-9]{3,30}$/.test(item.symbol) &&
                                (item.market === "spot" ||
                                    item.market === "futures"),
                        );
                    setWatchlist(items);
                })
                .catch((error: unknown) => {
                    if (
                        !active ||
                        controller.signal.aborted ||
                        (error instanceof DOMException &&
                            error.name === "AbortError")
                    )
                        return;
                    setWatchlistError(
                        error instanceof Error
                            ? error.message
                            : t("Watchlist could not be loaded."),
                    );
                })
                .finally(() => {
                    if (active && !controller.signal.aborted)
                        setWatchlistLoaded(true);
                });
        }, 0);

        return () => {
            active = false;
            window.clearTimeout(timer);
            controller.abort();
        };
    }, [universe, watchlistLoaded]);

    useEffect(() => {
        if (
            universe !== "market" ||
            sourcesLoading ||
            !selectedProvider ||
            catalogContext === catalogKey
        ) {
            return;
        }

        const controller = new AbortController();
        const timer = window.setTimeout(() => {
            setCatalogLoading(true);
            setCatalogError("");
            const query = new URLSearchParams({
                market,
                provider: selectedProvider,
            });

            void requestJson(
                `/market/catalog?${query.toString()}`,
                controller.signal,
            )
                .then((payload) => {
                    if (controller.signal.aborted) return;

                    const items = asRecordList(payload)
                        .map((item) => ({
                            symbol: String(item.symbol ?? "")
                                .toUpperCase()
                                .replace(/[\s/_-]+/g, ""),
                            market,
                        }))
                        .filter((item): item is WatchlistItem =>
                            /^[A-Z0-9]{3,30}$/.test(item.symbol),
                        )
                        .filter(
                            (item, index, all) =>
                                all.findIndex(
                                    (candidate) =>
                                        candidate.symbol === item.symbol,
                                ) === index,
                        );

                    setMarketCatalog(items);
                    setCatalogContext(catalogKey);
                })
                .catch((error: unknown) => {
                    if (
                        controller.signal.aborted ||
                        (error instanceof DOMException &&
                            error.name === "AbortError")
                    )
                        return;
                    setCatalogError(
                        error instanceof Error
                            ? error.message
                            : t("Market catalog could not be loaded."),
                    );
                })
                .finally(() => {
                    if (!controller.signal.aborted) setCatalogLoading(false);
                });
        }, 0);

        return () => {
            window.clearTimeout(timer);
            controller.abort();
            setCatalogLoading(false);
        };
    }, [
        universe,
        sourcesLoading,
        market,
        selectedProvider,
        catalogContext,
        catalogKey,
        catalogReloadVersion,
    ]);

    useEffect(
        () => () => {
            scanControllerRef.current?.abort();
            scanControllerRef.current = null;
        },
        [],
    );

    const startScan = useCallback(async () => {
        if (
            scanControllerRef.current ||
            scanItems.length === 0 ||
            !selectedProvider
        )
            return;
        const controller = new AbortController();
        scanControllerRef.current = controller;
        const queue = [...scanItems];
        const scanProvider = selectedProvider;
        const scanMarket = market;
        const scanInterval = interval;
        const scanMode = signalMode;
        const context = scanContext;

        setResults([]);
        setLastScanContext(context);
        setScanStatus("scanning");
        setProgress({ total: queue.length, completed: 0, currentSymbol: null });

        try {
            for (let index = 0; index < queue.length; index += 1) {
                if (controller.signal.aborted) break;
                const item = queue[index];
                setProgress({
                    total: queue.length,
                    completed: index,
                    currentSymbol: item.symbol,
                });
                const query = new URLSearchParams({
                    symbol: item.symbol,
                    market: scanMarket,
                    interval: scanInterval,
                    signal_mode: scanMode,
                    provider: scanProvider,
                });

                try {
                    const payload = await requestJson(
                        `/market-scanner/analyze?${query.toString()}`,
                        controller.signal,
                    );
                    if (controller.signal.aborted) break;
                    const result = parseAnalysis(
                        payload,
                        item,
                        scanProvider,
                        scanInterval,
                        scanMode,
                    );
                    setResults((current) => [...current, result]);
                } catch (error) {
                    if (
                        controller.signal.aborted ||
                        (error instanceof DOMException &&
                            error.name === "AbortError")
                    ) {
                        break;
                    }
                    setResults((current) => [
                        ...current,
                        errorResult(
                            item,
                            scanProvider,
                            scanInterval,
                            scanMode,
                            error instanceof Error
                                ? error.message
                                : "Analysis failed.",
                        ),
                    ]);
                }

                setProgress({
                    total: queue.length,
                    completed: index + 1,
                    currentSymbol:
                        index + 1 < queue.length
                            ? queue[index + 1].symbol
                            : null,
                });

                if (index + 1 < queue.length && !controller.signal.aborted) {
                    await new Promise<void>((resolve) => {
                        window.setTimeout(resolve, REQUEST_SPACING_MS);
                    });
                }
            }
        } finally {
            if (scanControllerRef.current === controller) {
                scanControllerRef.current = null;
                setScanStatus(
                    controller.signal.aborted ? "stopped" : "completed",
                );
                setProgress((current) => ({ ...current, currentSymbol: null }));
            }
        }
    }, [
        scanItems,
        selectedProvider,
        market,
        interval,
        signalMode,
        scanContext,
    ]);

    const stopScan = useCallback(() => {
        scanControllerRef.current?.abort();
    }, []);

    const reloadSources = useCallback(async () => {
        if (scanControllerRef.current) return;
        setSourcesLoading(true);
        setSourceError("");
        setCatalogError("");
        setCatalogContext("");
        setCatalogReloadVersion((version) => version + 1);
        if (universe === "watchlist") {
            setWatchlistLoaded(false);
            setWatchlistError("");
        }

        const controller = new AbortController();
        try {
            const providerPayload = await requestJson(
                "/market/providers",
                controller.signal,
            );
            if (controller.signal.aborted) return;
            const providerItems = asRecordList(providerPayload)
                .map((item): ProviderOption => {
                    const markets = Array.isArray(item.markets)
                        ? item.markets
                              .map((value) => String(value).toLowerCase())
                              .filter(
                                  (value): value is Market =>
                                      value === "spot" || value === "futures",
                              )
                        : [];

                    return {
                        name: String(item.name ?? item.slug ?? "Provider"),
                        slug: String(item.slug ?? "").toLowerCase(),
                        markets,
                    };
                })
                .filter(
                    (item) =>
                        /^[a-z0-9_-]{1,64}$/.test(item.slug) &&
                        item.markets.length > 0,
                );
            setProviders(providerItems);
            setProvider((current) =>
                providerItems.some((item) => item.slug === current)
                    ? current
                    : (providerItems[0]?.slug ?? "binance"),
            );
        } catch (error) {
            if (
                !(error instanceof DOMException && error.name === "AbortError")
            ) {
                setSourceError(
                    error instanceof Error
                        ? error.message
                        : "Provider list could not be loaded.",
                );
            }
        } finally {
            if (!controller.signal.aborted) setSourcesLoading(false);
        }
    }, [universe]);

    const modeDescription = MODE_OPTIONS.find(
        (mode) => mode.value === signalMode,
    )?.description;

    return (
        <>
            <Head title={t("Market Scanner")} />
            <div className="product-page-content mx-auto w-full max-w-[1600px] space-y-6">
                {/* --- HEADER MODERN & MENJUAL --- */}
                <div className="relative min-w-0 overflow-hidden rounded-2xl border border-border/70 bg-card p-4 shadow-sm sm:p-6 lg:p-7">
                    <div className="pointer-events-none absolute -right-16 -top-16 h-56 w-56 rounded-full bg-primary/5 blur-3xl" />
                    <div className="relative z-10 flex min-w-0 flex-col justify-between gap-5 lg:flex-row lg:items-center lg:gap-6">
                        <div className="flex min-w-0 items-start gap-4 sm:items-center">
                            <div className="shrink-0 rounded-xl bg-primary/10 p-3 text-primary">
                                <Radar className="size-6" />
                            </div>
                            <div className="space-y-1">
                                <Badge
                                    variant="secondary"
                                    className="mb-1 bg-primary/10 text-primary font-medium"
                                >
                                    <Zap className="size-3.5 mr-1" />
                                    {t("Market Discovery & Evidence Engine")}
                                </Badge>
                                <h1 className="text-2xl sm:text-3xl font-extrabold tracking-tight">
                                    {t("Market Scanner")}
                                </h1>
                                <p className="max-w-xl text-xs sm:text-sm text-muted-foreground">
                                    {t(
                                        "Discover assets with noteworthy market conditions, unusual behaviour, and strong analytical evidence so you can investigate faster.",
                                    )}
                                </p>
                            </div>
                        </div>
                        <div className="flex w-full flex-col gap-2 sm:flex-row sm:flex-wrap sm:items-center sm:gap-3 lg:w-auto">
                            <Button
                                variant="outline"
                                className="h-10 w-full px-4 shadow-none sm:w-auto"
                                onClick={() => void reloadSources()}
                                disabled={
                                    sourcesLoading || scanStatus === "scanning"
                                }
                            >
                                <RefreshCw
                                    className={`size-4 mr-2 ${sourcesLoading ? "animate-spin" : ""}`}
                                />
                                {t("Refresh Sources")}
                            </Button>
                            {scanStatus === "scanning" ? (
                                <Button
                                    variant="destructive"
                                    className="h-11 w-full animate-pulse px-5 shadow-lg shadow-destructive/20 sm:w-auto"
                                    onClick={stopScan}
                                >
                                    <Square className="size-4 mr-2 fill-current" />
                                    {t("Stop Scan")}
                                </Button>
                            ) : (
                                <Button
                                    className="h-10 w-full px-5 font-semibold shadow-sm sm:w-auto"
                                    onClick={() => void startScan()}
                                    disabled={
                                        sourcesLoading ||
                                        catalogLoading ||
                                        scanItems.length === 0 ||
                                        supportedProviders.length === 0 ||
                                        !selectedProvider
                                    }
                                >
                                    <Play className="size-4 mr-2 fill-current" />
                                    {t("Start Scan Session")}
                                </Button>
                            )}
                        </div>
                    </div>
                </div>

                <CustomerWorkspaceNav group="analysis" />

                <ScannerDiscoverySummary
                    analyzed={progress.completed}
                    confirmed={counts.confirmed}
                    candidate={counts.candidate}
                    blocked={counts.blocked + counts.error}
                    confidence={averageConfidence}
                />

                {/* --- STATS / METRIC CARDS --- */}
                <div className="grid min-w-0 gap-4 sm:grid-cols-2 xl:grid-cols-4">
                    <Card className="bg-card/60 backdrop-blur-md shadow-sm transition-all hover:border-primary/40 p-5 sm:p-6">
                        <CardHeader className="flex flex-row items-center justify-between p-0 pb-2">
                            <CardTitle className="text-xs sm:text-sm font-medium text-muted-foreground">
                                {t("Assets Reviewed")}
                            </CardTitle>
                            <Activity className="size-4 text-primary" />
                        </CardHeader>
                        <CardContent className="p-0">
                            <div className="text-2xl sm:text-3xl font-bold tabular-nums">
                                {progress.completed}{" "}
                                <span className="text-sm sm:text-base font-normal text-muted-foreground">
                                    / {progress.total || scanItems.length}
                                </span>
                            </div>
                            <p className="text-[11px] sm:text-xs text-muted-foreground mt-1">
                                {t("Assets reviewed in this scan")}
                            </p>
                        </CardContent>
                    </Card>

                    <Card className="border-primary/30 bg-linear-to-br from-primary/10 to-transparent shadow-sm p-5 sm:p-6">
                        <CardHeader className="flex flex-row items-center justify-between p-0 pb-2">
                            <CardTitle className="text-xs sm:text-sm font-medium text-success-500">
                                {t("Confirmed")}
                            </CardTitle>
                            <CheckCircle2 className="size-4 text-success-500" />
                        </CardHeader>
                        <CardContent className="p-0">
                            <div className="text-2xl sm:text-3xl font-bold tabular-nums text-success-500">
                                {counts.confirmed}
                            </div>
                            <p className="text-[11px] sm:text-xs text-muted-foreground mt-1">
                                {t("Passed the required confirmation checks")}
                            </p>
                        </CardContent>
                    </Card>

                    <Card className="border-warning-500/30 bg-linear-to-br from-warning-500/10 to-transparent shadow-sm p-5 sm:p-6">
                        <CardHeader className="flex flex-row items-center justify-between p-0 pb-2">
                            <CardTitle className="text-xs sm:text-sm font-medium text-warning-500">
                                {t("Candidate")}
                            </CardTitle>
                            <AlertTriangle className="size-4 text-warning-500" />
                        </CardHeader>
                        <CardContent className="p-0">
                            <div className="text-2xl sm:text-3xl font-bold tabular-nums text-warning-500">
                                {counts.candidate}
                            </div>
                            <p className="text-[11px] sm:text-xs text-muted-foreground mt-1">
                                {t("Promising setup, but confirmation is incomplete")}
                            </p>
                        </CardContent>
                    </Card>

                    <Card className="bg-card/60 backdrop-blur-md shadow-sm p-5 sm:p-6">
                        <CardHeader className="flex flex-row items-center justify-between p-0 pb-2">
                            <CardTitle className="text-xs sm:text-sm font-medium text-muted-foreground">
                                {t("Blocked / Unavailable")}
                            </CardTitle>
                            <ShieldCheck className="size-4 text-muted-foreground" />
                        </CardHeader>
                        <CardContent className="p-0">
                            <div className="text-2xl sm:text-3xl font-bold tabular-nums">
                                {counts.blocked + counts.error}
                            </div>
                            <p className="text-[11px] sm:text-xs text-muted-foreground mt-1">
                                {t("Difilter ketat manajemen risiko")}
                            </p>
                        </CardContent>
                    </Card>
                </div>

                {/* --- KONTROL PENGATURAN SCANNER --- */}
                <Card className="overflow-hidden">
                    <CardHeader className="border-b p-5 sm:p-6">
                        <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3">
                            <div>
                                <CardTitle className="text-base sm:text-lg font-semibold tracking-tight">
                                    {t("Session Parameter Configuration")}
                                </CardTitle>
                                <CardDescription className="text-xs sm:text-sm">
                                    {t(
                                        "Set the market scope and analysis engine precision.",
                                    )}
                                </CardDescription>
                            </div>
                            <Badge
                                variant="outline"
                                className="bg-secondary/50 py-1.5 px-3 text-xs font-medium text-muted-foreground gap-1.5 w-fit"
                            >
                                <Clock3 className="size-3.5 text-primary shrink-0" />{" "}
                                {t("Rate-limit delay: :seconds s / coin", {
                                    seconds: REQUEST_SPACING_MS / 1000,
                                })}
                            </Badge>
                        </div>
                    </CardHeader>
                    <CardContent className="p-5 sm:p-6 space-y-5">
                        <div className="grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3 2xl:grid-cols-6">
                            <div className="space-y-2 text-sm">
                                <Label className="text-xs font-medium text-muted-foreground sm:text-sm">
                                    {t("Market Type")}
                                </Label>
                                <Select
                                    value={market}
                                    onValueChange={(val) =>
                                        setMarket(val as Market)
                                    }
                                    disabled={scanStatus === "scanning"}
                                >
                                    <SelectTrigger className="h-11 rounded-xl font-medium w-full">
                                        <SelectValue
                                            placeholder={t("Select market")}
                                        />
                                    </SelectTrigger>
                                    <SelectContent>
                                        <SelectItem value="futures">
                                            {t("Futures")}
                                        </SelectItem>
                                        <SelectItem value="spot">
                                            {t("Spot")}
                                        </SelectItem>
                                    </SelectContent>
                                </Select>
                            </div>

                            <div className="space-y-2 text-sm">
                                <Label className="text-xs font-medium text-muted-foreground sm:text-sm">
                                    {t("Asset Source")}
                                </Label>
                                <Select
                                    value={universe}
                                    onValueChange={(val) =>
                                        setUniverse(val as ScanUniverse)
                                    }
                                    disabled={scanStatus === "scanning"}
                                >
                                    <SelectTrigger className="h-11 rounded-xl font-medium w-full">
                                        <SelectValue
                                            placeholder={t("Select source")}
                                        />
                                    </SelectTrigger>
                                    <SelectContent>
                                        <SelectItem value="market">
                                            {t("All")}
                                        </SelectItem>
                                        <SelectItem value="watchlist">
                                            {t("Watchlist")}
                                        </SelectItem>
                                    </SelectContent>
                                </Select>
                            </div>

                            <div className="space-y-2 text-sm">
                                <Label className="text-xs font-medium text-muted-foreground sm:text-sm">
                                    {t("Coin Limit")}
                                </Label>
                                <Select
                                    value={scanLimit}
                                    onValueChange={(val) =>
                                        setScanLimit(val as any)
                                    }
                                    disabled={scanStatus === "scanning"}
                                >
                                    <SelectTrigger className="h-11 rounded-xl font-medium w-full">
                                        <SelectValue
                                            placeholder={t("Select limit")}
                                        />
                                    </SelectTrigger>
                                    <SelectContent>
                                        {SCAN_LIMIT_OPTIONS.map((option) => (
                                            <SelectItem
                                                key={option.value}
                                                value={option.value}
                                            >
                                                {option.label}
                                            </SelectItem>
                                        ))}
                                    </SelectContent>
                                </Select>
                            </div>

                            <div className="space-y-2 text-sm">
                                <Label className="text-xs font-medium text-muted-foreground sm:text-sm">
                                    {t("Signal Mode")}
                                </Label>
                                <Select
                                    value={signalMode}
                                    onValueChange={(val) =>
                                        setSignalMode(val as SignalMode)
                                    }
                                    disabled={scanStatus === "scanning"}
                                >
                                    <SelectTrigger className="h-11 rounded-xl font-medium w-full">
                                        <SelectValue
                                            placeholder={t("Select mode")}
                                        />
                                    </SelectTrigger>
                                    <SelectContent>
                                        {MODE_OPTIONS.map((mode) => (
                                            <SelectItem
                                                key={mode.value}
                                                value={mode.value}
                                            >
                                                {t(mode.label)}
                                            </SelectItem>
                                        ))}
                                    </SelectContent>
                                </Select>
                            </div>

                            <div className="space-y-2 text-sm">
                                <Label className="text-xs font-medium text-muted-foreground sm:text-sm">
                                    {t("Timeframe")}
                                </Label>
                                <Select
                                    value={interval}
                                    onValueChange={setInterval}
                                    disabled={scanStatus === "scanning"}
                                >
                                    <SelectTrigger className="h-11 rounded-xl font-medium w-full">
                                        <SelectValue
                                            placeholder={t("Select timeframe")}
                                        />
                                    </SelectTrigger>
                                    <SelectContent>
                                        {INTERVALS.map((value) => (
                                            <SelectItem
                                                key={value}
                                                value={value}
                                            >
                                                {value}
                                            </SelectItem>
                                        ))}
                                    </SelectContent>
                                </Select>
                            </div>

                            <div className="space-y-2 text-sm">
                                <Label className="text-xs font-medium text-muted-foreground sm:text-sm">
                                    {t("Exchange Provider")}
                                </Label>
                                <Select
                                    value={selectedProvider}
                                    onValueChange={setProvider}
                                    disabled={
                                        scanStatus === "scanning" ||
                                        supportedProviders.length === 0
                                    }
                                >
                                    <SelectTrigger className="h-11 rounded-xl font-medium w-full">
                                        <SelectValue
                                            placeholder={t("Select provider")}
                                        />
                                    </SelectTrigger>
                                    <SelectContent>
                                        {supportedProviders.map((item) => (
                                            <SelectItem
                                                key={item.slug}
                                                value={item.slug}
                                            >
                                                {item.name}
                                            </SelectItem>
                                        ))}
                                    </SelectContent>
                                </Select>
                            </div>
                        </div>

                        <div className="rounded-xl border bg-secondary/30 p-4 flex flex-col sm:flex-row sm:items-center justify-between gap-3 text-xs">
                            <span className="text-foreground font-medium flex items-center gap-1.5">
                                <TrendingUp className="size-4 text-primary shrink-0" />{" "}
                                {modeDescription ? t(modeDescription) : ""}
                            </span>
                            <span className="text-muted-foreground shrink-0">
                                {universe === "watchlist"
                                    ? t(":count coins active in watchlist.", {
                                          count: selectedWatchlist.length,
                                      })
                                    : catalogLoading
                                      ? t(
                                            "Synchronizing market catalog and liquidity filters...",
                                        )
                                      : t(
                                            ":ready of :total coins ready to scan (~:delay)",
                                            {
                                                ready: scanItems.length,
                                                total: selectedMarketCatalog.length,
                                                delay: minimumDelayLabel,
                                            },
                                        )}
                            </span>
                        </div>

                        {sourceError && (
                            <div
                                role="alert"
                                className="rounded-xl border border-destructive/30 bg-destructive/10 p-3.5 text-sm text-destructive"
                            >
                                {sourceError}
                            </div>
                        )}
                        {watchlistError && (
                            <div
                                role="alert"
                                className="rounded-xl border border-destructive/30 bg-destructive/10 p-3.5 text-sm text-destructive"
                            >
                                {watchlistError}
                            </div>
                        )}
                        {catalogError && (
                            <div
                                role="alert"
                                className="rounded-xl border border-destructive/30 bg-destructive/10 p-3.5 text-sm text-destructive"
                            >
                                {catalogError}
                            </div>
                        )}

                        {universe === "watchlist" &&
                            watchlistLoaded &&
                            !watchlistError &&
                            selectedWatchlist.length === 0 && (
                                <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 rounded-xl border border-dashed p-5 bg-card/50">
                                    <div>
                                        <p className="font-semibold text-sm">
                                            {t(":market watchlist is empty", {
                                                market: market.toUpperCase(),
                                            })}
                                        </p>
                                        <p className="text-xs text-muted-foreground mt-0.5">
                                            {t(
                                                "Add assets directly from the interactive market analysis workspace.",
                                            )}
                                        </p>
                                    </div>
                                    <Button variant="outline" size="sm" asChild>
                                        <Link href="/trading/BTCUSDT">
                                            {t("Open Market Analysis")}{" "}
                                            <ExternalLink className="size-3.5 ml-1.5" />
                                        </Link>
                                    </Button>
                                </div>
                            )}
                    </CardContent>
                </Card>

                {/* --- HASIL SCANNER & FILTER PENCARIAN --- */}
                <Card className="overflow-hidden">
                    <CardHeader className="flex flex-col sm:flex-row sm:items-center justify-between gap-3 border-b p-5 sm:p-6">
                        <div>
                            <CardTitle className="text-base sm:text-lg font-semibold tracking-tight">
                                {t("Discovery Results")}
                            </CardTitle>
                            <CardDescription className="text-xs sm:text-sm">
                                {t(
                                    "Ranked research matches with the evidence available from the selected market, timeframe, and provider.",
                                )}
                            </CardDescription>
                        </div>
                        {scanStatus !== "scanning" && results.length > 0 && (
                            <Button
                                variant="outline"
                                size="sm"
                                onClick={() => {
                                    setResults([]);
                                    setProgress({
                                        total: 0,
                                        completed: 0,
                                        currentSymbol: null,
                                    });
                                    setScanStatus("idle");
                                    setLastScanContext("");
                                }}
                            >
                                {t("Clear Session")}
                            </Button>
                        )}
                    </CardHeader>
                    <CardContent className="p-5 sm:p-6 space-y-4">
                        {/* Progress Bar Indikator */}
                        {scanStatus === "scanning" && (
                            <div
                                className="space-y-2.5 rounded-xl border border-primary/20 bg-primary/5 p-4"
                                aria-live="polite"
                            >
                                <div className="flex flex-wrap items-center justify-between gap-2 text-sm font-medium">
                                    <span className="flex items-center gap-2 text-primary">
                                        <LoaderCircle className="size-4 animate-spin" />{" "}
                                        {t("Analyzing")}{" "}
                                        <strong className="font-bold text-foreground">
                                            {progress.currentSymbol ?? "..."}
                                        </strong>
                                    </span>
                                    <span className="tabular-nums text-muted-foreground">
                                        {t(":completed of :total (:percent%)", {
                                            completed: progress.completed,
                                            total: progress.total,
                                            percent: progressPercent,
                                        })}
                                    </span>
                                </div>
                                <div className="h-2.5 overflow-hidden rounded-full bg-background border">
                                    <div
                                        className="h-full rounded-full bg-linear-to-r from-primary/60 to-primary transition-all duration-300"
                                        style={{ width: `${progressPercent}%` }}
                                    />
                                </div>
                            </div>
                        )}

                        {resultsAreStale && (
                            <div className="rounded-xl border border-warning-500/30 bg-warning-500/10 p-4 text-sm text-warning-500 flex items-center gap-3">
                                <ShieldAlert className="size-5 shrink-0" />
                                <span>
                                    {t(
                                        "The parameter configuration changed since the last result. Run the scan again to synchronize the data.",
                                    )}
                                </span>
                            </div>
                        )}

                        {/* Filter & Toolbar Pencarian */}
                        <div className="flex flex-col lg:flex-row lg:items-center gap-3">
                            <div className="relative w-full lg:max-w-xs">
                                <Search className="absolute left-3.5 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
                                <Input
                                    value={search}
                                    onChange={(event) =>
                                        setSearch(event.target.value)
                                    }
                                    placeholder={t(
                                        "Search symbol (e.g. BTC)...",
                                    )}
                                    className="pl-10 h-11 rounded-xl w-full"
                                    aria-label={t("Search coins")}
                                />
                            </div>

                            <div className="w-full lg:w-55">
                                <Select
                                    value={confidenceFilter}
                                    onValueChange={(val) =>
                                        setConfidenceFilter(
                                            val as ConfidenceFilter,
                                        )
                                    }
                                >
                                    <SelectTrigger className="h-11 rounded-xl font-medium w-full">
                                        <SelectValue
                                            placeholder={t("Filter Confidence")}
                                        />
                                    </SelectTrigger>
                                    <SelectContent>
                                        {CONFIDENCE_FILTER_OPTIONS.map(
                                            (option) => (
                                                <SelectItem
                                                    key={option.value}
                                                    value={option.value}
                                                >
                                                    {t(option.label)}
                                                </SelectItem>
                                            ),
                                        )}
                                    </SelectContent>
                                </Select>
                            </div>

                            <div className="flex flex-wrap gap-1.5 lg:ml-auto">
                                {(
                                    [
                                        "all",
                                        "confirmed",
                                        "candidate",
                                        "blocked",
                                        "error",
                                    ] as const
                                ).map((filter) => (
                                    <Button
                                        key={filter}
                                        size="sm"
                                        variant={
                                            resultFilter === filter
                                                ? "default"
                                                : "outline"
                                        }
                                        className={`h-11 rounded-xl px-4 flex-1 sm:flex-none ${resultFilter === filter ? "shadow-md" : ""}`}
                                        onClick={() => setResultFilter(filter)}
                                    >
                                        {
                                            {
                                                all: t("All"),
                                                confirmed: t("Confirmed"),
                                                candidate: t("Candidate"),
                                                blocked: t("Blocked"),
                                                error: t("Error"),
                                            }[filter]
                                        }
                                    </Button>
                                ))}
                            </div>
                        </div>

                        {/* Tampilan Konten Data / Empty State */}
                        {sourcesLoading && results.length === 0 ? (
                            <div className="flex flex-col items-center justify-center gap-3 py-16 text-muted-foreground">
                                <LoaderCircle className="size-6 animate-spin text-primary" />
                                <p className="text-sm font-medium">
                                    {t(
                                        "Loading market provider connections...",
                                    )}
                                </p>
                            </div>
                        ) : visibleResults.length === 0 ? (
                            <div className="flex flex-col items-center justify-center gap-3 py-16 text-center border border-dashed rounded-2xl bg-card/40">
                                {scanStatus === "scanning" ? (
                                    <LoaderCircle className="size-9 animate-spin text-primary" />
                                ) : (
                                    <Radar className="size-9 text-muted-foreground/60" />
                                )}
                                <p className="font-semibold text-base">
                                    {results.length === 0
                                        ? t("No Scan Data Yet")
                                        : t("No Matching Results")}
                                </p>
                                <p className="max-w-md text-sm text-muted-foreground px-4">
                                    {results.length === 0
                                        ? t(
                                              "Set the parameters as needed, then click Start Scan Session to run an instant analysis.",
                                          )
                                        : t(
                                              "Adjust the status filter, confidence threshold, or search keyword.",
                                          )}
                                </p>
                            </div>
                        ) : (
                            <div className="space-y-3">
                                {visibleResults.map((item) => {
                                    const isUp =
                                        item.action === "LONG" ||
                                        item.action === "BUY";
                                    const isDown =
                                        item.action === "SHORT" ||
                                        item.action === "SELL";
                                    const actionColorClass = isUp
                                        ? "text-success-500 bg-success-500/10 border-success-500/20"
                                        : isDown
                                          ? "text-destructive-500 bg-destructive-500/10 border-destructive-500/20"
                                          : "text-muted-foreground bg-secondary";
                                    const params = new URLSearchParams({
                                        market: item.market,
                                        interval: item.interval,
                                        provider: item.provider,
                                        signal_mode: item.signalMode,
                                    });
                                    const chartUrl = `/trading/${encodeURIComponent(item.symbol)}?${params.toString()}`;

                                    return (
                                        <div
                                            key={`${item.market}:${item.symbol}`}
                                            className="group rounded-2xl border bg-card/60 backdrop-blur-sm p-4 sm:p-5 transition-all hover:border-primary/40 hover:shadow-lg hover:shadow-black/5 space-y-4"
                                        >
                                            <div className="grid min-w-0 gap-4 2xl:grid-cols-[minmax(0,1.3fr)_minmax(0,1fr)_minmax(0,1.5fr)_auto] 2xl:items-center">
                                                {/* Simbol & Aksi */}
                                                <div className="space-y-1.5">
                                                    <div className="flex flex-wrap items-center gap-2.5">
                                                        <h3 className="text-lg font-bold tracking-tight">
                                                            {item.symbol}
                                                        </h3>
                                                        <Badge
                                                            variant="secondary"
                                                            className="uppercase text-[10px]"
                                                        >
                                                            {item.market}
                                                        </Badge>
                                                        <Badge
                                                            variant="outline"
                                                            className={`inline-flex items-center gap-1.5 px-3 py-1 text-xs font-extrabold tracking-wider ${actionColorClass}`}
                                                        >
                                                            {(() => {
                                                                const Icon = directionIcon(item.action);
                                                                return <Icon className="size-4" />;
                                                            })()}
                                                            {directionLabel(item.action, t)}
                                                        </Badge>
                                                    </div>
                                                    <p className="text-xs text-muted-foreground flex items-center gap-1.5">
                                                        <span className="font-medium uppercase text-foreground">
                                                            {item.provider}
                                                        </span>{" "}
                                                        • {item.interval} •{" "}
                                                        {formatDate(
                                                            item.candleTime,
                                                        )}
                                                    </p>
                                                </div>

                                                {/* Score & Confidence */}
                                                <div className="grid grid-cols-2 gap-3 text-sm bg-secondary/30 rounded-xl p-3 border">
                                                    <div>
                                                        <p className="text-[11px] uppercase tracking-wider text-muted-foreground font-medium">
                                                            {t("Score")}
                                                        </p>
                                                        <p className="font-bold tabular-nums text-base">
                                                            {formatScore(
                                                                item.score,
                                                            )}
                                                        </p>
                                                    </div>
                                                    <div>
                                                        <p className="text-[11px] uppercase tracking-wider text-muted-foreground font-medium">
                                                            {t("Confidence")}
                                                        </p>
                                                        <p className="font-bold tabular-nums text-base text-primary">
                                                            {formatPercent(
                                                                item.confidence,
                                                            )}
                                                        </p>
                                                    </div>
                                                </div>

                                                {/* Harga, Entry, SL/TP, RR */}
                                                <div className="grid grid-cols-2 sm:grid-cols-4 gap-3 text-sm bg-secondary/30 rounded-xl p-3 border">
                                                    <div>
                                                        <p className="text-[11px] uppercase tracking-wider text-muted-foreground font-medium">
                                                            {t("Price")}
                                                        </p>
                                                        <p className="font-semibold tabular-nums">
                                                            {formatPrice(
                                                                item.price,
                                                            )}
                                                        </p>
                                                    </div>
                                                    <div>
                                                        <p className="text-[11px] uppercase tracking-wider text-muted-foreground font-medium">
                                                            {t("Reference")}
                                                        </p>
                                                        <p className="font-semibold tabular-nums text-primary">
                                                            {formatPrice(
                                                                item.entry,
                                                            )}
                                                        </p>
                                                    </div>
                                                    <div>
                                                        <p className="text-[11px] uppercase tracking-wider text-muted-foreground font-medium">
                                                            {t("Range / Reference")}
                                                        </p>
                                                        <p className="font-medium text-xs tabular-nums text-muted-foreground truncate">
                                                            {formatPrice(
                                                                item.stopLoss,
                                                            )}{" "}
                                                            /{" "}
                                                            {formatPrice(
                                                                item.takeProfit,
                                                            )}
                                                        </p>
                                                    </div>
                                                    <div>
                                                        <p className="text-[11px] uppercase tracking-wider text-muted-foreground font-medium">
                                                            {t("Risk context")}
                                                        </p>
                                                        <p className="font-bold tabular-nums text-success-500">
                                                            {formatRatio(
                                                                item.riskReward,
                                                            )}
                                                        </p>
                                                    </div>
                                                </div>

                                                {/* Status Badge & Aksi Tombol */}
                                                <div className="flex flex-wrap items-center justify-between gap-3 2xl:justify-end">
                                                    <Badge
                                                        variant="outline"
                                                        className={`inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-semibold ${
                                                            item.state ===
                                                            "confirmed"
                                                                ? "border-success-500/30 bg-success-500/10 text-success-500"
                                                                : item.state ===
                                                                    "candidate"
                                                                  ? "border-warning-500/30 bg-warning-500/10 text-warning-500"
                                                                  : item.state ===
                                                                      "error"
                                                                    ? "border-destructive-500/30 bg-destructive-500/10 text-destructive-500"
                                                                    : "border-border bg-secondary/50 text-muted-foreground"
                                                        }`}
                                                    >
                                                        {item.state ===
                                                        "error" ? (
                                                            <XCircle className="size-4" />
                                                        ) : item.state ===
                                                          "confirmed" ? (
                                                            <CheckCircle2 className="size-4" />
                                                        ) : (
                                                            <AlertTriangle className="size-4" />
                                                        )}
                                                        {t(
                                                            stateLabel(
                                                                item.state,
                                                            ),
                                                        )}
                                                    </Badge>
                                                    <Button
                                                        asChild
                                                        size="sm"
                                                        className="rounded-xl font-semibold shadow-sm h-9"
                                                    >
                                                        <a
                                                            href={chartUrl}
                                                            target="_blank"
                                                            rel="noopener noreferrer"
                                                        >
                                                            {t("Chart")}{" "}
                                                            <ExternalLink className="size-3.5 ml-1.5" />
                                                        </a>
                                                    </Button>
                                                </div>
                                            </div>

                                            {/* Pesan & Alasan Analisis */}
                                            {(item.message ||
                                                item.reasons.length > 0) && (
                                                <div className="rounded-xl bg-secondary/50 border px-4 py-3 text-xs text-muted-foreground space-y-1">
                                                    <p className="font-medium text-foreground">
                                                        {item.message}
                                                    </p>
                                                    {item.reasons.length >
                                                        0 && (
                                                        <p className="text-muted-foreground">
                                                            {item.reasons.join(
                                                                " • ",
                                                            )}
                                                        </p>
                                                    )}
                                                </div>
                                            )}

                                            {/* Rincian Pemeriksaan Gate (Collapsible) menggunakan struktur Table bawaan Shadcn UI */}
                                            {item.gateDetails.length > 0 && (
                                                <GateDetailsDisclosure
                                                    gates={item.gateDetails}
                                                    translate={t}
                                                />
                                            )}
                                        </div>
                                    );
                                })}
                            </div>
                        )}

                        {(scanStatus === "completed" ||
                            scanStatus === "stopped") &&
                            progress.total > 0 && (
                                <div
                                    className="text-center pt-4 border-t text-xs text-muted-foreground"
                                    role="status"
                                >
                                    {scanStatus === "completed"
                                        ? t(
                                              "Scan session completed successfully.",
                                          )
                                        : t("Scan was stopped manually.")}{" "}
                                    {t(
                                        "Showing results from :count analyzed coins.",
                                        { count: progress.completed },
                                    )}
                                </div>
                            )}
                    </CardContent>
                </Card>

                {/* --- DISCLAIMER FOOTER PROFESIONAL --- */}
                <div className="rounded-2xl border bg-secondary/30 p-4 sm:p-5 text-xs text-muted-foreground flex items-start gap-3">
                    <ShieldCheck className="size-5 text-primary shrink-0 mt-0.5" />
                    <div className="space-y-1">
                        <strong className="text-foreground font-semibold">
                            {t("Market Research Disclaimer")}
                        </strong>
                        <p>
                            {t(
                                "This scanner is an analytical discovery tool based on technical and market-structure evidence. Confidence reflects alignment with the analysis engine criteria and is not a probability or guarantee. Use the results as research context, not as execution instructions.",
                            )}
                        </p>
                    </div>
                </div>
            </div>
        </>
    );
}

function GateDetailsDisclosure({
    gates,
    translate,
}: {
    gates: GateDetail[];
    translate: ReturnType<typeof useI18n>["t"];
}) {
    const [open, setOpen] = useState(false);

    return (
        <Collapsible
            open={open}
            onOpenChange={setOpen}
            className="rounded-xl border bg-card/80 px-4 py-3 text-xs"
        >
            <CollapsibleTrigger asChild>
                <Button
                    variant="ghost"
                    className="h-auto w-full justify-start px-0 py-0 text-left font-semibold hover:bg-transparent"
                >
                    <Filter className="size-3.5 text-primary" />
                    {translate("Lihat Rincian Validasi Gate Sistem (")}{" "}
                    {gates.length})
                </Button>
            </CollapsibleTrigger>
            <CollapsibleContent>
                <div className="mt-3 overflow-x-auto border-t pt-2">
                    <Table className="min-w-[640px]">
                        <TableHeader>
                            <TableRow>
                                <TableHead>{translate("Check")}</TableHead>
                                <TableHead>{translate("Status")}</TableHead>
                                <TableHead>{translate("Stage")}</TableHead>
                                <TableHead>
                                    {translate("Value / Target")}
                                </TableHead>
                            </TableRow>
                        </TableHeader>
                        <TableBody>
                            {gates.map((gate) => {
                                const passed = gate.status === "pass";
                                const warned = gate.status === "warn";
                                const statusText = passed
                                    ? translate("Passed")
                                    : warned
                                      ? translate("Warning")
                                      : translate("Blocked");

                                return (
                                    <TableRow key={`${gate.key}:${gate.stage}`}>
                                        <TableCell className="font-medium text-foreground">
                                            {gate.label}
                                        </TableCell>
                                        <TableCell>
                                            <Badge
                                                variant="outline"
                                                className={`text-[10px] font-bold uppercase ${
                                                    passed
                                                        ? "border-success-500/20 bg-success-500/10 text-success-500"
                                                        : warned
                                                          ? "border-warning-500/20 bg-warning-500/10 text-warning-500"
                                                          : "border-destructive-500/20 bg-destructive-500/10 text-destructive-500"
                                                }`}
                                            >
                                                {statusText}
                                            </Badge>
                                        </TableCell>
                                        <TableCell className="text-muted-foreground">
                                            {gate.stage === "execution"
                                                ? translate("Entry Validation")
                                                : translate(
                                                      "Candidate Eligibility",
                                                  )}{" "}
                                            (
                                            {gate.severity === "hard"
                                                ? translate("Required")
                                                : translate("Supporting")}
                                            )
                                        </TableCell>
                                        <TableCell className="text-muted-foreground">
                                            {formatGateValue(gate.value)} /{" "}
                                            {formatGateValue(gate.target)}
                                        </TableCell>
                                    </TableRow>
                                );
                            })}
                        </TableBody>
                    </Table>
                </div>
            </CollapsibleContent>
        </Collapsible>
    );
}

MarketScanner.layout = (page: ReactNode) => (
    <AppLayout breadcrumbs={[{ title: "Market Scanner", href: "" }]}>
        {page}
    </AppLayout>
);
