import React, { useEffect, useMemo, useState } from 'react';
import { runBacktestApi } from '../api';
import type {
    BacktestIntraCandlePolicy,
    BacktestRequestPayload,
    BacktestResult,
    BacktestTimeframe,
    BacktestTriggerTimeframe
} from '../types';
import { parseSymbolsInput, toDateInputValue } from '../utils';
import { BacktestResultsDashboard } from './BacktestResultsDashboard';

type SourceType = 'csv' | 'json' | 'replay' | 'kraken';

export interface BacktestProfile {
    id: string;
    name: string;
    symbols: string;
    strategy_config: any;
    allocated_capital?: number;
}

interface CompareRow {
    profileId: string;
    profileName: string;
    status: 'success' | 'error';
    durationMs: number;
    result?: BacktestResult;
    error?: string;
}

interface BacktestComparePanelProps {
    profiles: BacktestProfile[];
}

const money = (value: number): string =>
    Number(value || 0).toLocaleString(undefined, { style: 'currency', currency: 'USD', maximumFractionDigits: 2 });

const pct = (value: number): string => `${Number(value || 0).toFixed(2)}%`;

export const BacktestComparePanel: React.FC<BacktestComparePanelProps> = ({ profiles }) => {
    const now = Date.now();
    const defaultFrom = toDateInputValue(now - (30 * 24 * 60 * 60 * 1000));
    const defaultTo = toDateInputValue(now);

    const [selectedProfileIds, setSelectedProfileIds] = useState<string[]>([]);
    const [timeframe, setTimeframe] = useState<BacktestTimeframe>('15m');
    const [fromDate, setFromDate] = useState(defaultFrom);
    const [toDate, setToDate] = useState(defaultTo);
    const [sourceType, setSourceType] = useState<SourceType>('kraken');
    const [sourcePayload, setSourcePayload] = useState<any>({ exchange: 'kraken' });
    const [sourceName, setSourceName] = useState('Kraken historical API');
    const [slippageBps, setSlippageBps] = useState(5);
    const [feeBps, setFeeBps] = useState(10);
    const [partialFillPct, setPartialFillPct] = useState(1);
    const [fillOnNextBar, setFillOnNextBar] = useState(true);
    const [intraCandlePolicy, setIntraCandlePolicy] = useState<BacktestIntraCandlePolicy>('ohlc_path');
    const [triggerTimeframe, setTriggerTimeframe] = useState<BacktestTriggerTimeframe>('1m');
    const [forceCloseAtWindowEnd, setForceCloseAtWindowEnd] = useState(false);
    const [krakenLookbackCandles, setKrakenLookbackCandles] = useState(2000);
    const [useNormalizedCapital, setUseNormalizedCapital] = useState(true);
    const [normalizedCapitalUsd, setNormalizedCapitalUsd] = useState(1000);
    const [running, setRunning] = useState(false);
    const [runningIndex, setRunningIndex] = useState(0);
    const [rows, setRows] = useState<CompareRow[]>([]);
    const [selectedResultProfileId, setSelectedResultProfileId] = useState<string>('');
    const [error, setError] = useState<string | null>(null);

    useEffect(() => {
        const existing = new Set(profiles.map((profile) => profile.id));
        setSelectedProfileIds((prev) => {
            const filtered = prev.filter((id) => existing.has(id));
            if (filtered.length) return filtered;
            return profiles.slice(0, Math.min(3, profiles.length)).map((profile) => profile.id);
        });
    }, [profiles]);

    const profileMap = useMemo(() => {
        const map = new Map<string, BacktestProfile>();
        for (const profile of profiles) {
            map.set(profile.id, profile);
        }
        return map;
    }, [profiles]);

    const selectedProfiles = useMemo(() => (
        selectedProfileIds
            .map((id) => profileMap.get(id))
            .filter((value): value is BacktestProfile => Boolean(value))
            .sort((a, b) => a.name.localeCompare(b.name))
    ), [selectedProfileIds, profileMap]);

    const successfulRows = useMemo(() => rows.filter((row) => row.status === 'success' && row.result), [rows]);
    const rankedRows = useMemo(() => {
        const success = successfulRows
            .slice()
            .sort((a, b) => (b.result?.summary.netPnlUsd || 0) - (a.result?.summary.netPnlUsd || 0));
        const errored = rows
            .filter((row) => row.status === 'error')
            .slice()
            .sort((a, b) => a.profileName.localeCompare(b.profileName));
        return [...success, ...errored];
    }, [successfulRows, rows]);

    const selectedResultRow = useMemo(
        () => rows.find((row) => row.profileId === selectedResultProfileId && row.result),
        [rows, selectedResultProfileId]
    );

    const readFile = async (file: File): Promise<void> => {
        const text = await file.text();
        setSourceName(file.name);
        if (sourceType === 'csv') {
            setSourcePayload(text);
            return;
        }
        try {
            const parsed = JSON.parse(text);
            setSourcePayload(parsed);
        } catch {
            throw new Error('Failed to parse JSON file.');
        }
    };

    const buildPayload = (profile: BacktestProfile): BacktestRequestPayload => {
        const parsedSymbols = parseSymbolsInput(profile.symbols || '');
        const initialCapital = useNormalizedCapital
            ? Number(normalizedCapitalUsd || 0)
            : Number(profile.allocated_capital || 1000);

        return {
            mode: 'backtest',
            profileId: profile.id,
            strategyConfig: profile.strategy_config,
            symbols: parsedSymbols,
            timeframe,
            dateRange: {
                from: new Date(`${fromDate}T00:00:00.000Z`).toISOString(),
                to: new Date(`${toDate}T23:59:59.999Z`).toISOString()
            },
            dataSource: {
                type: sourceType,
                payload: sourceType === 'kraken'
                    ? {
                        exchange: 'kraken',
                        lookbackCandles: Number(krakenLookbackCandles || 2000)
                    }
                    : (sourceType === 'csv' ? String(sourcePayload || '') : sourcePayload)
            },
            execution: {
                initialCapitalUsd: initialCapital,
                orderType: 'market',
                slippageBps: Number(slippageBps),
                feeBps: Number(feeBps),
                partialFillPct: Number(partialFillPct),
                fillOnNextBar,
                intraCandlePolicy,
                triggerTimeframe,
                enforceWarmup: true,
                allowNegativeCash: false,
                forceCloseAtWindowEnd
            }
        };
    };

    const runCompare = async () => {
        setError(null);
        if (selectedProfiles.length < 2) {
            setError('Select at least two strategy profiles to compare.');
            return;
        }
        if (!fromDate || !toDate) {
            setError('Please provide both from/to dates.');
            return;
        }
        if (new Date(`${toDate}T23:59:59.999Z`).getTime() < new Date(`${fromDate}T00:00:00.000Z`).getTime()) {
            setError('To date must be greater than or equal to From date.');
            return;
        }
        if (sourceType !== 'kraken' && !sourcePayload) {
            setError('Please upload historical data before running comparison.');
            return;
        }
        if (useNormalizedCapital && Number(normalizedCapitalUsd || 0) <= 0) {
            setError('Normalized capital must be greater than zero.');
            return;
        }

        setRunning(true);
        setRunningIndex(0);
        setRows([]);
        setSelectedResultProfileId('');

        const nextRows: CompareRow[] = [];
        for (let index = 0; index < selectedProfiles.length; index += 1) {
            const profile = selectedProfiles[index];
            setRunningIndex(index + 1);
            const startedAt = Date.now();
            try {
                const payload = buildPayload(profile);
                if (!payload.symbols.length) {
                    throw new Error('Profile has no symbols configured.');
                }
                const result = await runBacktestApi(payload);
                nextRows.push({
                    profileId: profile.id,
                    profileName: profile.name,
                    status: 'success',
                    durationMs: Date.now() - startedAt,
                    result
                });
            } catch (runError: any) {
                nextRows.push({
                    profileId: profile.id,
                    profileName: profile.name,
                    status: 'error',
                    durationMs: Date.now() - startedAt,
                    error: runError?.message || 'Backtest compare run failed'
                });
            }
            setRows([...nextRows]);
        }

        const firstSuccess = nextRows.find((row) => row.status === 'success');
        if (firstSuccess) {
            setSelectedResultProfileId(firstSuccess.profileId);
        }
        setRunning(false);
        setRunningIndex(0);
    };

    const toggleProfile = (profileId: string, checked: boolean) => {
        setSelectedProfileIds((prev) => {
            if (checked) {
                if (prev.includes(profileId)) return prev;
                return [...prev, profileId];
            }
            return prev.filter((id) => id !== profileId);
        });
    };

    return (
        <div className="space-y-4">
            <div className="rounded-2xl border border-indigo-400/20 bg-gradient-to-br from-zinc-950 to-zinc-900 p-4 space-y-3">
                <div className="flex items-center justify-between gap-3">
                    <div>
                        <h3 className="text-base font-black uppercase tracking-wide text-white">Compare Strategies</h3>
                        <p className="text-xs text-zinc-400">Run one deterministic replay window across multiple profiles and rank outcomes.</p>
                    </div>
                    <div className="text-[11px] text-zinc-500">
                        Selected: <span className="text-zinc-300 font-semibold">{selectedProfiles.length}</span>
                    </div>
                </div>

                <div className="rounded-xl border border-white/10 bg-zinc-950/70 p-3">
                    <div className="flex items-center justify-between mb-2">
                        <span className="text-[11px] font-bold uppercase tracking-wider text-zinc-300">Profiles</span>
                        <div className="flex gap-2">
                            <button
                                type="button"
                                className="rounded-md bg-white/10 px-2 py-1 text-[10px] font-bold uppercase tracking-wide text-zinc-300 hover:bg-white/20"
                                onClick={() => setSelectedProfileIds(profiles.map((profile) => profile.id))}
                            >
                                Select All
                            </button>
                            <button
                                type="button"
                                className="rounded-md bg-white/10 px-2 py-1 text-[10px] font-bold uppercase tracking-wide text-zinc-300 hover:bg-white/20"
                                onClick={() => setSelectedProfileIds([])}
                            >
                                Clear
                            </button>
                        </div>
                    </div>
                    <div className="grid grid-cols-1 md:grid-cols-2 gap-2 max-h-[180px] overflow-auto">
                        {profiles.map((profile) => (
                            <label key={profile.id} className="flex items-center gap-2 rounded-lg border border-white/10 bg-zinc-900/60 px-2 py-2">
                                <input
                                    type="checkbox"
                                    checked={selectedProfileIds.includes(profile.id)}
                                    onChange={(event) => toggleProfile(profile.id, event.target.checked)}
                                />
                                <span className="text-xs text-zinc-200">{profile.name}</span>
                                <span className="ml-auto text-[10px] text-zinc-500">{profile.symbols}</span>
                            </label>
                        ))}
                    </div>
                </div>

                <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
                    <label className="space-y-1">
                        <span className="text-[10px] uppercase tracking-wider text-zinc-400">Timeframe</span>
                        <select
                            value={timeframe}
                            onChange={(event) => setTimeframe(event.target.value as BacktestTimeframe)}
                            className="w-full rounded-lg border border-white/10 bg-zinc-900 px-3 py-2 text-xs text-white"
                        >
                            <option value="1m">1m</option>
                            <option value="15m">15m</option>
                            <option value="1h">1h</option>
                            <option value="4h">4h</option>
                        </select>
                    </label>
                    <label className="space-y-1">
                        <span className="text-[10px] uppercase tracking-wider text-zinc-400">Historical Data Type</span>
                        <select
                            value={sourceType}
                            onChange={(event) => {
                                const nextType = event.target.value as SourceType;
                                setSourceType(nextType);
                                if (nextType === 'kraken') {
                                    setSourcePayload({ exchange: 'kraken' });
                                    setSourceName('Kraken historical API');
                                } else {
                                    setSourcePayload(null);
                                    setSourceName('');
                                }
                            }}
                            className="w-full rounded-lg border border-white/10 bg-zinc-900 px-3 py-2 text-xs text-white"
                        >
                            <option value="kraken">Kraken Historical API</option>
                            <option value="csv">CSV</option>
                            <option value="json">JSON</option>
                            <option value="replay">Replay JSON</option>
                        </select>
                    </label>
                    <label className="space-y-1">
                        <span className="text-[10px] uppercase tracking-wider text-zinc-400">From</span>
                        <input
                            type="date"
                            value={fromDate}
                            onChange={(event) => setFromDate(event.target.value)}
                            className="w-full rounded-lg border border-white/10 bg-zinc-900 px-3 py-2 text-xs text-white"
                        />
                    </label>
                    <label className="space-y-1">
                        <span className="text-[10px] uppercase tracking-wider text-zinc-400">To</span>
                        <input
                            type="date"
                            value={toDate}
                            onChange={(event) => setToDate(event.target.value)}
                            className="w-full rounded-lg border border-white/10 bg-zinc-900 px-3 py-2 text-xs text-white"
                        />
                    </label>
                    <label className="space-y-1">
                        <span className="text-[10px] uppercase tracking-wider text-zinc-400">Slippage (bps)</span>
                        <input
                            type="number"
                            min={0}
                            value={slippageBps}
                            onChange={(event) => setSlippageBps(Number(event.target.value))}
                            className="w-full rounded-lg border border-white/10 bg-zinc-900 px-3 py-2 text-xs text-white"
                        />
                    </label>
                    <label className="space-y-1">
                        <span className="text-[10px] uppercase tracking-wider text-zinc-400">Fee (bps)</span>
                        <input
                            type="number"
                            min={0}
                            value={feeBps}
                            onChange={(event) => setFeeBps(Number(event.target.value))}
                            className="w-full rounded-lg border border-white/10 bg-zinc-900 px-3 py-2 text-xs text-white"
                        />
                    </label>
                    <label className="space-y-1">
                        <span className="text-[10px] uppercase tracking-wider text-zinc-400">Partial Fill %</span>
                        <input
                            type="number"
                            min={1}
                            max={100}
                            value={Math.round(partialFillPct * 100)}
                            onChange={(event) => setPartialFillPct(Math.max(0.01, Math.min(1, Number(event.target.value) / 100)))}
                            className="w-full rounded-lg border border-white/10 bg-zinc-900 px-3 py-2 text-xs text-white"
                        />
                    </label>
                    <label className="space-y-1">
                        <span className="text-[10px] uppercase tracking-wider text-zinc-400">Signal Fill Timing</span>
                        <select
                            value={fillOnNextBar ? 'next_open' : 'same_close'}
                            onChange={(event) => setFillOnNextBar(event.target.value === 'next_open')}
                            className="w-full rounded-lg border border-white/10 bg-zinc-900 px-3 py-2 text-xs text-white"
                        >
                            <option value="next_open">Next bar open</option>
                            <option value="same_close">Same bar close</option>
                        </select>
                    </label>
                    <label className="space-y-1">
                        <span className="text-[10px] uppercase tracking-wider text-zinc-400">Intra-candle Conflict</span>
                        <select
                            value={intraCandlePolicy}
                            onChange={(event) => setIntraCandlePolicy(event.target.value as BacktestIntraCandlePolicy)}
                            className="w-full rounded-lg border border-white/10 bg-zinc-900 px-3 py-2 text-xs text-white"
                        >
                            <option value="ohlc_path">OHLC path</option>
                            <option value="stop_loss_first">Stop-loss first</option>
                            <option value="take_profit_first">Take-profit first</option>
                        </select>
                    </label>
                    <label className="space-y-1">
                        <span className="text-[10px] uppercase tracking-wider text-zinc-400">Trigger Resolution</span>
                        <select
                            value={triggerTimeframe}
                            onChange={(event) => setTriggerTimeframe(event.target.value as BacktestTriggerTimeframe)}
                            className="w-full rounded-lg border border-white/10 bg-zinc-900 px-3 py-2 text-xs text-white"
                        >
                            <option value="1m">1m trigger candles</option>
                            <option value="off">Base timeframe only</option>
                        </select>
                    </label>
                </div>

                <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
                    <label className="space-y-1">
                        <span className="text-[10px] uppercase tracking-wider text-zinc-400">End-of-Window Position Handling</span>
                        <select
                            value={forceCloseAtWindowEnd ? 'force_close' : 'open_at_end'}
                            onChange={(event) => setForceCloseAtWindowEnd(event.target.value === 'force_close')}
                            className="w-full rounded-lg border border-white/10 bg-zinc-900 px-3 py-2 text-xs text-white"
                        >
                            <option value="open_at_end">Mark as OPEN_AT_END (Default)</option>
                            <option value="force_close">Force close at last candle</option>
                        </select>
                    </label>
                    {sourceType === 'kraken' ? (
                        <label className="space-y-1">
                            <span className="text-[10px] uppercase tracking-wider text-zinc-400">Kraken Warm-up Lookback Candles</span>
                            <input
                                type="number"
                                min={100}
                                value={krakenLookbackCandles}
                                onChange={(event) => setKrakenLookbackCandles(Math.max(100, Number(event.target.value || 0)))}
                                className="w-full rounded-lg border border-white/10 bg-zinc-900 px-3 py-2 text-xs text-white"
                            />
                        </label>
                    ) : (
                        <label className="space-y-1">
                            <span className="text-[10px] uppercase tracking-wider text-zinc-400">Upload Historical File</span>
                            <input
                                type="file"
                                accept={sourceType === 'csv' ? '.csv,text/csv' : '.json,application/json'}
                                onChange={async (event) => {
                                    try {
                                        const file = event.target.files?.[0];
                                        if (!file) return;
                                        await readFile(file);
                                        setError(null);
                                    } catch (uploadError: any) {
                                        setError(uploadError.message || 'Failed to read file');
                                    }
                                }}
                                className="w-full rounded-lg border border-white/10 bg-zinc-900 px-3 py-2 text-xs text-zinc-300"
                            />
                        </label>
                    )}
                </div>

                <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
                    <label className="flex items-center gap-2 text-xs text-zinc-300">
                        <input
                            type="checkbox"
                            checked={useNormalizedCapital}
                            onChange={(event) => setUseNormalizedCapital(event.target.checked)}
                        />
                        Normalize initial capital across compared strategies
                    </label>
                    <label className="space-y-1">
                        <span className="text-[10px] uppercase tracking-wider text-zinc-400">
                            {useNormalizedCapital ? 'Normalized Capital (USD)' : 'Capital Source'}
                        </span>
                        {useNormalizedCapital ? (
                            <input
                                type="number"
                                min={1}
                                value={normalizedCapitalUsd}
                                onChange={(event) => setNormalizedCapitalUsd(Number(event.target.value))}
                                className="w-full rounded-lg border border-white/10 bg-zinc-900 px-3 py-2 text-xs text-white"
                            />
                        ) : (
                            <div className="rounded-lg border border-white/10 bg-zinc-900 px-3 py-2 text-xs text-zinc-400">
                                Uses each profile allocated capital value.
                            </div>
                        )}
                    </label>
                </div>

                <div className="text-[11px] text-zinc-500">
                    Source: <span className="text-zinc-300">{sourceName || 'none'}</span>
                </div>

                {error && (
                    <div className="rounded-lg border border-red-500/30 bg-red-500/10 px-3 py-2 text-xs text-red-300">
                        {error}
                    </div>
                )}

                <button
                    onClick={() => { void runCompare(); }}
                    disabled={running}
                    className={`w-full rounded-xl px-4 py-2 text-xs font-black uppercase tracking-wider transition-colors ${running
                        ? 'bg-zinc-800 text-zinc-500 cursor-not-allowed'
                        : 'bg-indigo-400 text-black hover:bg-indigo-300'
                        }`}
                >
                    {running
                        ? `Running compare... (${runningIndex}/${selectedProfiles.length})`
                        : 'Run Strategy Comparison'}
                </button>
            </div>

            {rows.length > 0 && (
                <div className="rounded-2xl border border-white/10 bg-zinc-950/70 overflow-hidden">
                    <div className="px-4 py-3 border-b border-white/10 flex items-center justify-between">
                        <h4 className="text-xs font-bold uppercase tracking-wider text-zinc-300">Comparison Results</h4>
                        <span className="text-[11px] text-zinc-500">
                            Success: {successfulRows.length} / {rows.length}
                        </span>
                    </div>
                    <div className="overflow-x-auto">
                        <table className="w-full text-left text-xs">
                            <thead className="bg-zinc-900 text-zinc-500 uppercase tracking-wider text-[10px]">
                                <tr>
                                    <th className="px-3 py-2">Rank</th>
                                    <th className="px-3 py-2">Strategy</th>
                                    <th className="px-3 py-2">Net PnL</th>
                                    <th className="px-3 py-2">Win Rate</th>
                                    <th className="px-3 py-2">Max DD</th>
                                    <th className="px-3 py-2">Sharpe</th>
                                    <th className="px-3 py-2">Trades</th>
                                    <th className="px-3 py-2">Duration</th>
                                    <th className="px-3 py-2">Details</th>
                                </tr>
                            </thead>
                            <tbody className="divide-y divide-white/5">
                                {rankedRows.map((row, index) => {
                                    const summary = row.result?.summary;
                                    const active = row.profileId === selectedResultProfileId;
                                    return (
                                        <tr key={row.profileId} className={active ? 'bg-indigo-500/15' : 'hover:bg-white/5'}>
                                            <td className="px-3 py-2 text-zinc-300">
                                                {row.status === 'success' ? `#${index + 1}` : '-'}
                                            </td>
                                            <td className="px-3 py-2 text-white">{row.profileName}</td>
                                            <td className={`px-3 py-2 font-semibold ${summary && summary.netPnlUsd >= 0 ? 'text-emerald-400' : 'text-rose-400'}`}>
                                                {summary ? money(summary.netPnlUsd) : '-'}
                                            </td>
                                            <td className="px-3 py-2 text-zinc-300">{summary ? pct(summary.winRate) : '-'}</td>
                                            <td className="px-3 py-2 text-zinc-300">{summary ? pct(summary.maxDrawdownPct) : '-'}</td>
                                            <td className="px-3 py-2 text-zinc-300">{summary ? summary.sharpe.toFixed(3) : '-'}</td>
                                            <td className="px-3 py-2 text-zinc-300">{summary ? summary.totalTrades : '-'}</td>
                                            <td className="px-3 py-2 text-zinc-300">{(row.durationMs / 1000).toFixed(1)}s</td>
                                            <td className="px-3 py-2">
                                                {row.status === 'success' && row.result ? (
                                                    <button
                                                        type="button"
                                                        className="rounded-md bg-white/10 px-2 py-1 text-[10px] font-bold uppercase tracking-wide text-zinc-200 hover:bg-white/20"
                                                        onClick={() => setSelectedResultProfileId(row.profileId)}
                                                    >
                                                        Open
                                                    </button>
                                                ) : (
                                                    <span className="text-[11px] text-rose-300">{row.error || 'Run failed'}</span>
                                                )}
                                            </td>
                                        </tr>
                                    );
                                })}
                            </tbody>
                        </table>
                    </div>
                </div>
            )}

            {selectedResultRow?.result && (
                <div className="space-y-2">
                    <h4 className="text-sm font-bold uppercase tracking-wide text-white">
                        Detailed Result: {selectedResultRow.profileName}
                    </h4>
                    <BacktestResultsDashboard result={selectedResultRow.result} />
                </div>
            )}
        </div>
    );
};
