import type {
    BaselineSeriesOptions,
    CandlestickData,
    IChartApi,
    ISeriesApi,
    PriceLineOptions,
    SeriesMarker,
    SeriesMarkerShape,
    Time,
    UTCTimestamp,
} from 'lightweight-charts'
import {createChart, CrosshairMode, LineStyle} from 'lightweight-charts'
import moment from 'moment'
import * as React from 'react'
import {useEffect, useRef, useState} from 'react'

import type {
    Candle,
    IndicatorsResultBase,
    IndicatorType,
    KeyValuePairOfDateTimeAndDecimal,
    LightSignal,
    Position,
} from '../../../../generated/ManagingApi'
import {PositionStatus, TradeDirection,} from '../../../../generated/ManagingApi'
import useTheme from '../../../../hooks/useTheme'

// var customTheme = {
//     background: '#0B0B0B',
//     neutral: '#151515',
//     primary: '#54B5F9',
//     secondary: '#C492B1',
//     third: '#B0DB43',
//     fourth: '#F2D398',
//     fifth: '#99EDCC',
//     red: '#FF5340',
//     green: '#08C25F',
//     orange: '#EB6F22',
// }



type ITradeChartProps = {
    candles: Candle[]
    positions: Position[]
    signals: LightSignal[]
    walletBalances?: KeyValuePairOfDateTimeAndDecimal[] | null
    indicatorsValues?: { [key in keyof typeof IndicatorType]?: IndicatorsResultBase; } | null;
    stream?: Candle | null
    width?: number
    height?: number
}

const TradeChart = ({
                        candles,
                        positions,
                        signals,
                        walletBalances,
                        indicatorsValues,
                        stream,
                        width,
                        height,
                    }: ITradeChartProps) => {
    const chartRef = React.useRef<HTMLDivElement>(null)
    const containerRef = React.useRef<HTMLDivElement>(null)
    const chart = useRef<IChartApi>()
    const {themeProperty} = useTheme()
    const theme = themeProperty()
    const series1 = useRef<ISeriesApi<'Candlestick'>>()
    const [timeDiff, setTimeDiff] = useState<number>(0)
    const [candleCount, setCandleCount] = useState<number>(candles.length)
    const [chartDimensions, setChartDimensions] = useState({ width: 0, height: 0 })

    // Get responsive dimensions
    const getResponsiveDimensions = () => {
        if (!containerRef.current) return { width: width || 510, height: height || 300 }
        
        const containerWidth = containerRef.current.offsetWidth
        const containerHeight = containerRef.current.offsetHeight
        
        // Use provided dimensions if available, otherwise calculate responsive ones
        if (width && height) {
            return { width, height }
        }
        
        // For responsive mode, calculate based on container
        const calculatedWidth = containerWidth > 0 ? containerWidth : 510
        
        // Use different aspect ratios for different screen sizes
        let aspectRatio = 0.6 // Default ratio (height/width)
        if (containerWidth < 768) { // Mobile
            aspectRatio = 0.8 // Taller on mobile for better visibility
        } else if (containerWidth < 1024) { // Tablet
            aspectRatio = 0.65
        }
        
        const calculatedHeight = height || Math.max(250, calculatedWidth * aspectRatio)
        
        return {
            width: calculatedWidth,
            height: calculatedHeight
        }
    }

    // Resize observer to handle container size changes
    useEffect(() => {
        if (!containerRef.current) return

        const resizeObserver = new ResizeObserver(() => {
            const newDimensions = getResponsiveDimensions()
            setChartDimensions(newDimensions)
            
            if (chart.current) {
                chart.current.applyOptions({
                    width: newDimensions.width,
                    height: newDimensions.height
                })
            }
        })

        resizeObserver.observe(containerRef.current)

        return () => {
            resizeObserver.disconnect()
        }
    }, [width, height])

    // Handle window resize for additional responsiveness
    useEffect(() => {
        const handleResize = () => {
            setTimeout(() => {
                const newDimensions = getResponsiveDimensions()
                setChartDimensions(newDimensions)
                
                if (chart.current) {
                    chart.current.applyOptions({
                        width: newDimensions.width,
                        height: newDimensions.height
                    })
                }
            }, 100) // Small delay to ensure container has updated
        }

        window.addEventListener('resize', handleResize)
        return () => window.removeEventListener('resize', handleResize)
    }, [width, height])

    function buildLine(
        color: string,
        price: number,
        title: string
    ): PriceLineOptions {
        return {
            axisLabelVisible: true,
            color: color,
            lineStyle: LineStyle.Dotted,
            lineVisible: true,
            lineWidth: 1,
            price: price,
            title: title,
        }
    }

    const baselineOptions: BaselineSeriesOptions = {
        bottomLineColor: theme?.secondary ?? theme.primary,
        topLineColor: theme.primary,
        lineWidth: 1,
        priceLineVisible: true,
        crosshairMarkerVisible: true,
    } as BaselineSeriesOptions

    function buildMarker(
        shape: SeriesMarkerShape,
        color: string,
        direction: TradeDirection,
        date: Date,
        text?: string
    ): SeriesMarker<Time> {
        return {
            color: color,
            position: direction == TradeDirection.Long ? 'belowBar' : 'aboveBar',
            shape: shape,
            size: 1,
            text: text,
            time: moment(date).unix() as UTCTimestamp,
        }
    }

    function mapCandle(c: Candle): CandlestickData {
        return {
            close: c.close,
            high: c.high,
            low: c.low,
            open: c.open,
            time: moment(c.date).unix() as UTCTimestamp,
        }
    }

    function mergeTickToBar(candle: CandlestickData) {
        const previousCandle = series1.current?.dataByIndex(
            candleCount - 1
        ) as CandlestickData

        if ((candle.time as number) - (previousCandle?.time as number) > timeDiff) {
            series1.current?.update(candle)
            setCandleCount((prev) => prev + 1)
        } else {
            previousCandle.close = candle.close
            previousCandle.high = Math.max(previousCandle.high, candle.high)
            previousCandle.low = Math.min(previousCandle.low, candle.low)
            series1.current?.update(previousCandle)
        }
    }

    function getPositionColor(position: Position) {
        let color = 'mintcream'
        if (position == undefined) return color

        const negativeColor = theme.error
        const positiveColor = theme.success
        const status = position.status
        const realized = position.ProfitAndLoss?.realized ?? 0

        if (status != undefined) {
            if (
                status == PositionStatus.Finished ||
                status == PositionStatus.Flipped
            ) {
                if (realized > 0) {
                    color = positiveColor
                } else {
                    color = negativeColor
                }
            }else if (status == PositionStatus.Filled) {
                color = theme.warning
            }
        }

        return color
    }

    useEffect(() => {
        if (chartRef.current && containerRef.current) {
            const initialDimensions = getResponsiveDimensions()
            setChartDimensions(initialDimensions)
            
            const lineColor = theme['base-100']
            chart.current = createChart(chartRef.current, {
                crosshair: {
                    mode: CrosshairMode.Normal,
                    vertLine: {
                        color: theme.accent,
                        width: 1,
                        style: LineStyle.Solid,
                        visible: true,
                        labelVisible: true,
                    },
                    horzLine: {
                        color: theme.accent,
                        width: 1,
                        style: LineStyle.Solid,
                        visible: true,
                        labelVisible: true,
                    },
                },
                grid: {
                    horzLines: {
                        color: lineColor,
                        visible: false,
                    },
                    vertLines: {
                        color: lineColor,
                        visible: false,
                    },
                },
                height: initialDimensions.height,
                layout: {
                    background: {color: theme['base-300']},
                    textColor: theme.accent,
                },
                localization: {
                    dateFormat: 'yyyy-MM-dd',
                },
                rightPriceScale: {
                    autoScale: true,
                    borderColor: lineColor,
                    borderVisible: true,
                },
                timeScale: {
                    borderColor: lineColor,
                    lockVisibleTimeRangeOnResize: true,
                    secondsVisible: true,
                    timeVisible: true,
                },
                width: initialDimensions.width,
            })

            prepareChart()
        }
    }, [])

    useEffect(() => {
        if (series1.current === null) {
            return
        }

        if (stream && candles.length > 1 && timeDiff) {
            const c = mapCandle(stream)
            mergeTickToBar(c)
        }
    }, [stream])

    function prepareChart() {
        if (!chart.current) return

        series1.current = chart.current.addCandlestickSeries({
            borderDownColor: theme.accent,
            borderUpColor: theme.primary,
            downColor: theme.accent,
            upColor: theme.primary,
            wickDownColor: theme.accent,
            wickUpColor: theme.primary,
        })

        const data: CandlestickData[] = candles.map((c) => mapCandle(c))
        let diff = 0; // Default to 0 if there's not enough data to calculate the difference

        if (data.length > 3) {
            diff =
                (data[data.length - 1].time as number) -
                (data[data.length - 2].time as number);
        }

        setTimeDiff(diff)
        setCandleCount(data.length)

        series1.current.setData(data)
        series1.current.applyOptions({
            priceFormat: {
                minMove: 0.0001,
                precision: 4,
                type: 'price',
            },
        })

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

        if (signals && candles.length > 0) {
            // Get the time range of candles
            const firstCandleTime = moment(candles[0].date).unix()
            const lastCandleTime = moment(candles[candles.length - 1].date).unix()
            
            // Filter signals that are within the candle range
            const filteredSignals = signals.filter((s) => {
                const signalTime = moment(s.date).unix()
                return signalTime >= firstCandleTime && signalTime <= lastCandleTime
            })
            
            const signalMarkers = filteredSignals.map((s) =>
                buildMarker(
                    'circle',
                    s.direction == TradeDirection.Long ? theme.success : theme.error,
                    s.direction,
                    s.date,
                    undefined
                )
            )
            markers.push(...signalMarkers)
        }

        if (positions) {
            const positionMarkers = positions.map((p) =>
                buildMarker(
                    p.originDirection == TradeDirection.Long ? 'arrowUp' : 'arrowDown',
                    getPositionColor(p),
                    p.originDirection,
                    p.date,
                    p.Open?.price?.toString()
                )
            )

            markers.push(...positionMarkers)

            const lastPositionOpen = positions[positions.length - 1]
            if (lastPositionOpen) {
                series1.current.createPriceLine(
                    buildLine(theme.error, lastPositionOpen.StopLoss?.price, 'SL')
                )
                series1.current.createPriceLine(
                    buildLine(theme.success, lastPositionOpen.TakeProfit1?.price, 'TP')
                )
            }
        }

        // Price panel
        if (indicatorsValues?.EmaTrend != null || indicatorsValues?.EmaCross != null) 
        {
           const emaSeries = chart.current.addLineSeries({
                color: theme.secondary,
                lineWidth: 1,
                priceLineVisible: true,
                priceLineWidth: 1,
                priceFormat: {
                    minMove: 0.0001,
                    precision: 4,
                    type: 'price',
                },
                title: 'EMA',
            })

            const ema = indicatorsValues.EmaTrend?.ema ?? indicatorsValues.EmaCross?.ema

            const emaData = ema?.map((w) => {
                return {
                    time: moment(w.date).unix(),
                    value: w.ema,
                }
            })

            if (emaData != null)
            {
                // @ts-ignore
                emaSeries.setData(emaData)
            }
        }

        if (indicatorsValues?.SuperTrend != null) {
            const superTrendSeries = chart.current.addLineSeries({
                color: theme.info,
                lineWidth: 1,
                priceLineVisible: false,
                priceLineWidth: 1,
                priceLineColor: theme.info,
                title: 'SuperTrend',
                pane: 0,

            })

            const superTrend = indicatorsValues.SuperTrend.superTrend?.map((w) => {
                return {
                    time: moment(w.date).unix(),
                    value: w.superTrend,
                }
            })
            // @ts-ignore
            superTrendSeries.setData(superTrend)
        }

          // Display chandeliers exits
          if (indicatorsValues?.ChandelierExit != null) {
            const chandelierExitsLongsSeries = chart.current.addLineSeries({
                color: theme.info,
                lineWidth: 1,
                priceLineVisible: false,
                priceLineWidth: 1,
                title: 'Chandelier Long',
                pane: 0,
            })

            const chandelierExitsLongs = indicatorsValues.ChandelierExit.chandelierLong?.map((w) => {
                return {
                    time: moment(w.date).unix(),
                    value: w.chandelierExit,
                }
            })
            // @ts-ignore
            chandelierExitsLongsSeries.setData(chandelierExitsLongs)

            const chandelierExitsShortsSeries = chart.current.addLineSeries({
                color: theme.error,
                lineWidth: 1,
                priceLineVisible: false,
                priceLineWidth: 1,
                title: 'Chandelier Short',
                pane: 0,
            })

            const chandelierExitsShorts = indicatorsValues.ChandelierExit.chandelierShort?.map((w) => {
                return {
                    time: moment(w.date).unix(),
                    value: w.chandelierExit,
                }
            })

            // @ts-ignore
            chandelierExitsShortsSeries.setData(chandelierExitsShorts)
        }

        if (markers.length > 0) {
            series1.current.setMarkers(markers)
        }

        // Indicator panel
        var paneCount = 1

        
        if (indicatorsValues?.RsiDivergence != null || indicatorsValues?.RsiDivergenceConfirm != null) 
        {
            const rsiSeries = chart.current.addLineSeries({
                pane: paneCount,
                title: 'RSI',
            })

            const rsi = indicatorsValues.RsiDivergence?.rsi ?? indicatorsValues.RsiDivergenceConfirm?.rsi

            const rsiData = rsi?.map((w) => {
                return {
                    time: moment(w.date).unix(),
                    value: w.rsi,
                }
            })
            // @ts-ignore
            rsiSeries.setData(rsiData)
            rsiSeries.applyOptions({
                ...baselineOptions,
                priceFormat: {
                    minMove: 0.01,
                    precision: 4,
                    type: 'price',
                },
            })
            paneCount++
        }

        if (indicatorsValues?.Stc != null) {
            const stcSeries = chart.current.addBaselineSeries({
                pane: paneCount,
                baseValue: {price: 50, type: 'price'},
            
                title: 'STC',
            })

            stcSeries.createPriceLine(buildLine(theme.error, 25, 'low'))
            stcSeries.createPriceLine(buildLine(theme.info, 75, 'high'))

            const stcData = indicatorsValues?.Stc.stc?.map((w) => {
                return {
                    time: moment(w.date).unix(),
                    value: w.stc,
                }
            })
            // @ts-ignore
            stcSeries.setData(stcData)
            stcSeries.applyOptions({
                ...baselineOptions,
                priceLineVisible: true,
                priceFormat: {
                    minMove: 1,
                    precision: 1,
                    type: 'price',
                },
                crosshairMarkerVisible: true,
            })

            paneCount++
        }

        if (indicatorsValues?.LaggingStc != null) {
            const laggingStcSeries = chart.current.addBaselineSeries({
                pane: paneCount,
                baseValue: {price: 50, type: 'price'},
            
                title: 'Lagging STC',
            })

            laggingStcSeries.createPriceLine(buildLine(theme.error, 25, 'low'))
            laggingStcSeries.createPriceLine(buildLine(theme.info, 75, 'high'))

            const stcData = indicatorsValues?.LaggingStc.stc?.map((w) => {
                return {
                    time: moment(w.date).unix(),
                    value: w.stc,
                }
            })
            // @ts-ignore
            laggingStcSeries.setData(stcData)
            laggingStcSeries.applyOptions({
                ...baselineOptions,
                priceLineVisible: true,
                priceFormat: {
                    minMove: 1,
                    precision: 1,
                    type: 'price',
                },
                crosshairMarkerVisible: true,
            })

            paneCount++
        }

        console.log(indicatorsValues)
        if (indicatorsValues?.MacdCross != null) {
            console.log(indicatorsValues.MacdCross)
            const histogramSeries = chart.current.addHistogramSeries({
                color: theme.accent,
                title: 'MACD',
                pane: paneCount,
                priceFormat: {
                    precision: 6,
                    type: 'volume',
                }
            })

            const macd = indicatorsValues.MacdCross.macd?.map((w) => {
                return {
                    time: moment(w.date).unix(),
                    value: w.histogram,
                }
            })

            var priceOptions = {
                scaleMargins:{
                    top: 0.7,
                    bottom: 0.02,
                }
            }
            histogramSeries.priceScale().applyOptions(priceOptions)
            // @ts-ignore
            histogramSeries.setData(macd)

            const macdSeries = chart.current.addLineSeries({
                color: theme.primary,
                lineWidth: 1,
                priceLineVisible: false,
                priceLineWidth: 1,
                title: 'EMA',
                pane: paneCount,
                priceFormat: {
                    precision: 6,
                    type: 'price',
                },
                crosshairMarkerVisible: true,
            })

            const macdData = indicatorsValues.MacdCross.macd?.map((w) => {
                return {
                    time: moment(w.date).unix(),
                    value: w.macd,
                }
            })

            macdSeries.priceScale().applyOptions(priceOptions)
            // @ts-ignore
            macdSeries.setData(macdData) 

            const signalSeries = chart.current.addLineSeries({
                color: theme.info,
                lineWidth: 1,
                priceLineVisible: false,
                priceLineWidth: 1,
                lineStyle: LineStyle.Dotted,
                title: 'Signal',
                pane: paneCount,
                priceFormat: {
                    precision: 6,
                    type: 'price',
                },
            })

            const signalData = indicatorsValues.MacdCross.macd?.map((w) => {
                return {
                    time: moment(w.date).unix(),
                    value: w.signal,
                }
            })
            signalSeries.priceScale().applyOptions(priceOptions)
            // @ts-ignore
            signalSeries.setData(signalData)
          
            paneCount++
        }

        if (indicatorsValues?.StochRsiTrend){
            const stochRsiSeries = chart.current.addLineSeries({
                ...baselineOptions,
                priceLineVisible: false,
                title: 'Stoch RSI',
                pane: paneCount,
            })

            const stochRsi = indicatorsValues.StochRsiTrend.stochRsi?.map((w) => {
                return {
                    time: moment(w.date).unix(),
                    value: w.stochRsi,
                }
            })
            // @ts-ignore
            stochRsiSeries.setData(stochRsi)
            paneCount++
        }

        if (indicatorsValues?.StDev != null) {
            const stDevSeries = chart.current.addLineSeries({
                color: theme.primary,
                lineWidth: 1,
                priceLineVisible: false,
                priceLineWidth: 1,
                title: 'StDev',
                pane: paneCount,
            })

            const stDev = indicatorsValues.StDev.stdDev?.map((w) => {
                return {
                    time: moment(w.date).unix(),
                    value: w.stdDev,
                }
            })
            // @ts-ignore
            stDevSeries.setData(stDev)
            paneCount++

            const zScoreSeries = chart.current.addBaselineSeries({
                ...baselineOptions,
                baseValue: {price: 0, type: 'price'},
                title: 'ZScore',
                pane: paneCount,
                crosshairMarkerVisible: true,
            })

            const zScore = indicatorsValues.StDev.stdDev?.map((w) => {
                return {
                    time: moment(w.date).unix(),
                    value: w.zScore,
                }
            })
            // @ts-ignore
            zScoreSeries.setData(zScore)

            paneCount++
        }

      
        // Display dual EMA crossover
        if (indicatorsValues?.DualEmaCross != null) {
            const fastEmaSeries = chart.current.addLineSeries({
                color: theme.info,
                lineWidth: 1,
                priceLineVisible: false,
                priceLineWidth: 1,
                title: 'Fast EMA',
                pane: paneCount,
            })

            const fastEma = indicatorsValues.DualEmaCross.fastEma?.map((w) => {
                return {
                    time: moment(w.date).unix(),
                    value: w.ema,
                }
            })
            // @ts-ignore
            fastEmaSeries.setData(fastEma)

            const slowEmaSeries = chart.current.addLineSeries({
                color: theme.primary,
                lineWidth: 1,
                priceLineVisible: false,
                priceLineWidth: 1,
                title: 'Slow EMA',
                pane: paneCount,
            })

            const slowEma = indicatorsValues.DualEmaCross.slowEma?.map((w) => {
                return {
                    time: moment(w.date).unix(),
                    value: w.ema,
                }
            })
            // @ts-ignore
            slowEmaSeries.setData(slowEma)
            paneCount++
        }

        if (walletBalances != null && walletBalances.length > 0) {
            const walletSeries = chart.current.addBaselineSeries({
                baseValue: {price: walletBalances[0].value, type: 'price'},
                pane: paneCount,
                title: '$',
            })

            const walletData = walletBalances.map((w) => {
                return {
                    time: moment(w.key).unix(),
                    value: w.value,
                }
            })
            // @ts-ignore
            walletSeries.setData(walletData)
            walletSeries.applyOptions({
                ...baselineOptions,
                priceFormat: {
                    minMove: 0.0001,
                    precision: 4,
                    type: 'price',
                },

            })
            paneCount++
        }
    }

    return (
        <div 
            ref={containerRef} 
            className="w-full h-full"
            style={{ minHeight: height || 250 }}
        >
            <div ref={chartRef} className="w-full h-full" />
        </div>
    )
}

export default TradeChart
