import { useEffect, useRef } from "react";
import {
    createSeriesMarkers,
    LineStyle,
    type IPriceLine,
    type ISeriesApi,
    type ISeriesMarkersPluginApi,
    type SeriesMarker,
    type Time,
} from "lightweight-charts";

import type { BacktestResult } from "../../lib/backtest-types";

export type BacktestChartHandle = {
    series: ISeriesApi<"Candlestick">;
    resetView: () => void;
};

interface BacktestChartOverlayProps {
    chart: BacktestChartHandle | null;
    result: BacktestResult | null;
    selectedTradeIndex: number | null;
}

/**
 * Renders Backtest ENTRY / EXIT markers and the selected trade's
 * SL / TP price lines on the existing candlestick series.
 *
 * Lightweight Charts v5 uses createSeriesMarkers() for markers.
 */
export default function BacktestChartOverlay({
    chart,
    result,
    selectedTradeIndex,
}: BacktestChartOverlayProps) {
    // Explicitly type the ref with Time. Without this, TypeScript can
    // infer `unknown` and later reject the Time-specific marker plugin.
    const markersRef = useRef<ISeriesMarkersPluginApi<Time> | null>(null);
    const priceLinesRef = useRef<IPriceLine[]>([]);

    useEffect(() => {
        const series = chart?.series;

        if (!series) {
            return;
        }

        // Always clear the previous overlay before applying the new one.
        markersRef.current?.detach();
        markersRef.current = null;

        for (const line of priceLinesRef.current) {
            series.removePriceLine(line);
        }
        priceLinesRef.current = [];

        if (!result?.trades?.length) {
            return;
        }

        const markers: SeriesMarker<Time>[] = [];

        result.trades.forEach((trade, index) => {
            const tradeId = `bt-${index}`;

            markers.push({
                id: `${tradeId}-entry`,
                time: trade.entry_time as Time,
                position: trade.direction === "long" ? "belowBar" : "aboveBar",
                shape: trade.direction === "long" ? "arrowUp" : "arrowDown",
                color: trade.direction === "long" ? "#10b981" : "#ef4444",
                text: `ENTRY ${index + 1}`,
                size: 1,
            });

            markers.push({
                id: `${tradeId}-exit`,
                time: trade.exit_time as Time,
                position: trade.net_pnl >= 0 ? "aboveBar" : "belowBar",
                shape: "circle",
                color: trade.net_pnl >= 0 ? "#22c55e" : "#f97316",
                text: `EXIT ${trade.reason.replaceAll("_", " ")}`,
                size: 1,
            });
        });

        markersRef.current = createSeriesMarkers<Time>(series, markers, {
            autoScale: false,
            zOrder: "top",
        });

        /*
         * Only the selected trade gets SL/TP lines. Drawing two lines for
         * every trade would make a large backtest unreadable.
         *
         * Copy the value first so TypeScript keeps the null narrowing
         * across the following indexed access.
         */
        const selectedIndex = selectedTradeIndex;

        if (
            selectedIndex !== null &&
            selectedIndex >= 0 &&
            selectedIndex < result.trades.length
        ) {
            const selectedTrade = result.trades[selectedIndex];

            const slLine = series.createPriceLine({
                price: selectedTrade.sl,
                color: "#ef4444",
                lineWidth: 1,
                lineStyle: LineStyle.Dashed,
                axisLabelVisible: true,
                title: `SL #${selectedIndex + 1}`,
            });

            const tpLine = series.createPriceLine({
                price: selectedTrade.tp,
                color: "#10b981",
                lineWidth: 1,
                lineStyle: LineStyle.Dashed,
                axisLabelVisible: true,
                title: `TP #${selectedIndex + 1}`,
            });

            priceLinesRef.current = [slLine, tpLine];
        }

        return () => {
            markersRef.current?.detach();
            markersRef.current = null;

            for (const line of priceLinesRef.current) {
                series.removePriceLine(line);
            }

            priceLinesRef.current = [];
        };
    }, [chart, result, selectedTradeIndex]);

    return null;
}
