import {ChevronDownIcon, ChevronRightIcon, PlayIcon, TrashIcon} from '@heroicons/react/solid'
import React, {useEffect, useState} from 'react'

import useApiUrlStore from '../../../app/store/apiStore'
import type {Backtest} from '../../../generated/ManagingApi'
import {BacktestClient} from '../../../generated/ManagingApi'
import type {IBacktestCards} from '../../../global/type'
import {CardText, SelectColumnFilter, Table} from '../../mollecules'
import BotConfigModal from '../../mollecules/BotConfigModal/BotConfigModal'
import Toast from '../../mollecules/Toast/Toast'

import BacktestRowDetails from './backtestRowDetails'

const BacktestTable: React.FC<IBacktestCards> = ({ list, isFetching, setBacktests }) => {
  const [rows, setRows] = useState<Backtest[]>([])
  const { apiUrl } = useApiUrlStore()
  const [optimizedMoneyManagement, setOptimizedMoneyManagement] = useState({
    stopLoss: 0,
    takeProfit: 0,
  })
  const [positionTimingStats, setPositionTimingStats] = useState({
    averageOpenTime: 0,
    medianOpenTime: 0,
    losingPositionsAverageOpenTime: 0,
  })
  const [cooldownRecommendations, setCooldownRecommendations] = useState({
    averageCooldown: 0,
    medianCooldown: 0,
  })
  
  // Bot configuration modal state
  const [showBotConfigModal, setShowBotConfigModal] = useState(false)
  const [selectedBacktest, setSelectedBacktest] = useState<Backtest | null>(null)

  const handleOpenBotConfigModal = (backtest: Backtest) => {
    setSelectedBacktest(backtest)
    setShowBotConfigModal(true)
  }

  const handleCloseBotConfigModal = () => {
    setShowBotConfigModal(false)
    setSelectedBacktest(null)
  }

  async function deleteBacktest(id: string) {
    const t = new Toast('Deleting backtest')
    const client = new BacktestClient({}, apiUrl)

    await client
      .backtest_DeleteBacktest(id)
      .then(() => {
        t.update('success', 'Backtest deleted')
        // Remove the deleted backtest from the list
        if (list) {
          const updatedList = list.filter(backtest => backtest.id !== id);
          setBacktests(updatedList);
        }
      })
      .catch((err) => {
        t.update('error', err)
      })
  }

  const getScoreColor = (score: number) => {
    if (score >= 75) return '#08C25F'; // success
    if (score >= 50) return '#B0DB43'; // info
    if (score >= 25) return '#EB6F22'; // warning
    return '#FF5340'; // error
  };

  const columns = React.useMemo(
    () => [
      {
        Header: 'Informations',
        columns: [
          {
            Cell: ({ row }: any) => (
              // Use Cell to render an expander for each row.
              // We can use the getToggleRowExpandedProps prop-getter
              // to build the expander.
              <span {...row.getToggleRowExpandedProps()}>
                {row.isExpanded ? (
                  <ChevronDownIcon></ChevronDownIcon>
                ) : (
                  <ChevronRightIcon></ChevronRightIcon>
                )}
              </span>
            ),

            // Make sure it has an ID
            Header: ({
              getToggleAllRowsExpandedProps,
              isAllRowsExpanded,
            }: any) => (
              <span {...getToggleAllRowsExpandedProps()}>
                {isAllRowsExpanded ? 'v' : '>'}
              </span>
            ),
            // Build our expander column
            id: 'expander',
          },
          {
            Header: 'Score',
            accessor: 'score',
            Cell: ({ cell }: any) => (
              <span style={{ 
                color: getScoreColor(cell.row.values.score),
                fontWeight: 500,
                display: 'inline-block',
                width: '60px'
              }}>
                {cell.row.values.score.toFixed(2)}
              </span>
            ),
            disableFilters: true,
          },
          {
            Filter: SelectColumnFilter,
            Header: 'Ticker',
            accessor: 'config.ticker',
            disableSortBy: true,
          },
         
          {
            Filter: SelectColumnFilter,
            Header: 'Timeframe',
            accessor: 'config.timeframe',
            disableSortBy: true,
          },
          {
            Filter: SelectColumnFilter,
            Header: 'Scenario',
            accessor: 'config.scenarioName',
            disableSortBy: true,
          },
          {
            Filter: SelectColumnFilter,
            Header: 'BotType',
            accessor: 'config.botType',
            disableSortBy: true,
          },
        ],
      },
      {
        Header: 'Results',
        columns: [
          {
            Cell: ({ cell }: any) => (
              <>{cell.row.values.finalPnl.toFixed(2)} $</>
            ),
            Header: 'Pnl $',
            accessor: 'finalPnl',
            disableFilters: true,
            sortType: 'basic',
          },
          {
            Cell: ({ cell }: any) => (
              <>{cell.row.values.hodlPercentage.toFixed(2)} %</>
            ),
            Header: 'Hodl %',
            accessor: 'hodlPercentage',
            disableFilters: true,
            sortType: 'basic',
          },
          {
            Cell: ({ cell }: any) => <>{cell.row.values.winRate} %</>,
            Header: 'Winrate',
            accessor: 'winRate',
            disableFilters: true,
          },
          {
            Cell: ({ cell }: any) => (
              <>{cell.row.values.growthPercentage.toFixed(2)} %</>
            ),
            Header: 'Pnl %',
            accessor: 'growthPercentage',
            disableFilters: true,
            sortType: 'basic',
          },
          {
            Cell: ({ cell }: any) => (
              <>
                {(
                  cell.row.values.growthPercentage -
                  cell.row.values.hodlPercentage
                ).toFixed(2)}
              </>
            ),
            Header: 'H/P',
            accessor: 'diff',
            disableFilters: true,
            sortType: 'basic',
          },
        ],
      },
      {
        Header: 'Action',
        columns: [
          {
            Cell: ({ cell }: any) => (
              <>
                <div className="tooltip" data-tip="Delete backtest">
                  <button
                    data-value={cell.row.values.name}
                    onClick={() => deleteBacktest(cell.row.values.id)}
                  >
                    <TrashIcon className="text-accent w-4"></TrashIcon>
                  </button>
                </div>
              </>
            ),
            Header: '',
            accessor: 'id',
            disableFilters: true,
          },
          {
            Cell: ({ cell }: any) => (
              <>
                <div className="tooltip" data-tip="Create bot from backtest">
                  <button
                    data-value={cell.row.values.name}
                    onClick={() => handleOpenBotConfigModal(cell.row.original as Backtest)}
                  >
                    <PlayIcon className="text-primary w-4"></PlayIcon>
                  </button>
                </div>
              </>
            ),
            Header: '',
            accessor: 'runner',
            disableFilters: true,
          }
        ],
      },
    ],
    []
  )

  useEffect(() => {
    if (list) {
      setRows(list)
      
      // Calculate average optimized money management
      if (list.length > 0) {
        const optimized = list.map((b) => b.optimizedMoneyManagement);
        const stopLoss = optimized.reduce((acc, curr) => acc + (curr?.stopLoss ?? 0), 0);
        const takeProfit = optimized.reduce((acc, curr) => acc + (curr?.takeProfit ?? 0), 0);
        
        setOptimizedMoneyManagement({
          stopLoss: stopLoss / optimized.length,
          takeProfit: takeProfit / optimized.length,
        });

        // Calculate position timing statistics
        const allPositions = list.flatMap(backtest => backtest.positions);
        const finishedPositions = allPositions.filter(p => p.status === 'Finished');
        
        if (finishedPositions.length > 0) {
          // Calculate position open times in hours
          const openTimes = finishedPositions.map(position => {
            const openTime = new Date(position.open.date);
            // Find the closing trade (either stopLoss or takeProfit that was filled)
            let closeTime = new Date();
            
            if (position.stopLoss.status === 'Filled') {
              closeTime = new Date(position.stopLoss.date);
            } else if (position.takeProfit1.status === 'Filled') {
              closeTime = new Date(position.takeProfit1.date);
            } else if (position.takeProfit2?.status === 'Filled') {
              closeTime = new Date(position.takeProfit2.date);
            }
            
            // Return time difference in hours
            return (closeTime.getTime() - openTime.getTime()) / (1000 * 60 * 60);
          });

          // Calculate average
          const averageOpenTime = openTimes.reduce((sum, time) => sum + time, 0) / openTimes.length;

          // Calculate median
          const sortedTimes = [...openTimes].sort((a, b) => a - b);
          const medianOpenTime = sortedTimes.length % 2 === 0
            ? (sortedTimes[sortedTimes.length / 2 - 1] + sortedTimes[sortedTimes.length / 2]) / 2
            : sortedTimes[Math.floor(sortedTimes.length / 2)];

          // Calculate average for losing positions
          const losingPositions = finishedPositions.filter(p => (p.profitAndLoss?.realized ?? 0) < 0);
          let losingPositionsAverageOpenTime = 0;
          
          if (losingPositions.length > 0) {
            const losingOpenTimes = losingPositions.map(position => {
              const openTime = new Date(position.open.date);
              let closeTime = new Date();
              
              if (position.stopLoss.status === 'Filled') {
                closeTime = new Date(position.stopLoss.date);
              } else if (position.takeProfit1.status === 'Filled') {
                closeTime = new Date(position.takeProfit1.date);
              } else if (position.takeProfit2?.status === 'Filled') {
                closeTime = new Date(position.takeProfit2.date);
              }
              
              return (closeTime.getTime() - openTime.getTime()) / (1000 * 60 * 60);
            });
            
            losingPositionsAverageOpenTime = losingOpenTimes.reduce((sum, time) => sum + time, 0) / losingOpenTimes.length;
          }

          setPositionTimingStats({
            averageOpenTime,
            medianOpenTime,
            losingPositionsAverageOpenTime,
          });
        }

        // Calculate cooldown recommendations across all backtests
        const allCooldownValues: number[] = [];
        
        list.forEach(backtest => {
          if (backtest.positions.length < 2 || !backtest.candles || backtest.candles.length < 2) {
            return;
          }

          // Determine candle timeframe in milliseconds
          const candleTimeframeMs = new Date(backtest.candles[1].date).getTime() - new Date(backtest.candles[0].date).getTime();

          const sortedPositions = [...backtest.positions].sort((a, b) => {
            const dateA = new Date(a.open.date).getTime();
            const dateB = new Date(b.open.date).getTime();
            return dateA - dateB;
          });

          for (let i = 0; i < sortedPositions.length - 1; i++) {
            const currentPosition = sortedPositions[i];
            const nextPosition = sortedPositions[i + 1];

            const currentRealized = currentPosition.profitAndLoss?.realized ?? 0;
            const nextRealized = nextPosition.profitAndLoss?.realized ?? 0;

            // Check if current position is winning and next position is losing
            if (currentRealized > 0 && nextRealized <= 0) {
              // Calculate the close time of the current (winning) position
              let currentCloseDate: Date | null = null;
              if (currentPosition.profitAndLoss?.realized != null) {
                if (currentPosition.profitAndLoss.realized > 0) {
                  currentCloseDate = new Date(currentPosition.takeProfit1.date);
                } else {
                  currentCloseDate = new Date(currentPosition.stopLoss.date);
                }
              }

              if (currentCloseDate) {
                const nextOpenDate = new Date(nextPosition.open.date);
                const gapInMs = nextOpenDate.getTime() - currentCloseDate.getTime();
                
                if (gapInMs >= 0) { // Only consider positive gaps
                  // Convert milliseconds to number of candles
                  const gapInCandles = Math.floor(gapInMs / candleTimeframeMs);
                  allCooldownValues.push(gapInCandles);
                }
              }
            }
          }
        });

        if (allCooldownValues.length > 0) {
          // Calculate average cooldown
          const averageCooldown = allCooldownValues.reduce((sum, value) => sum + value, 0) / allCooldownValues.length;

          // Calculate median cooldown
          const sortedCooldowns = [...allCooldownValues].sort((a, b) => a - b);
          const medianCooldown = sortedCooldowns.length % 2 === 0
            ? (sortedCooldowns[sortedCooldowns.length / 2 - 1] + sortedCooldowns[sortedCooldowns.length / 2]) / 2
            : sortedCooldowns[Math.floor(sortedCooldowns.length / 2)];

          setCooldownRecommendations({
            averageCooldown: Math.ceil(averageCooldown),
            medianCooldown: Math.ceil(medianCooldown),
          });
        }
      }
    }
  }, [list])

  return (
    <>
      {isFetching ? (
        <div className="flex justify-center">
          <progress className="progress progress-primary w-56"></progress>
        </div>
      ) : (
        <>
          {list && list.length > 0 && (
            <>
              <div className="mb-4">
                <CardText
                  title="Average Optimized Money Management"
                  content={
                    "SL: " + optimizedMoneyManagement.stopLoss.toFixed(2) + "% | TP: " + 
                    optimizedMoneyManagement.takeProfit.toFixed(2) + "% | R/R: " + 
                    (optimizedMoneyManagement.takeProfit / optimizedMoneyManagement.stopLoss || 0).toFixed(2)
                  }
                />
              </div>
              <div className="mb-4">
                <CardText
                  title="Position Timing Statistics"
                  content={
                    "Avg: " + positionTimingStats.averageOpenTime.toFixed(1) + "h | " +
                    "Median: " + positionTimingStats.medianOpenTime.toFixed(1) + "h | " +
                    "Losing Avg: " + positionTimingStats.losingPositionsAverageOpenTime.toFixed(1) + "h"
                  }
                />
              </div>
              <div className="mb-4">
                <CardText
                  title="Cooldown Recommendations"
                  content={
                    "Avg: " + cooldownRecommendations.averageCooldown + " candles | " +
                    "Median: " + cooldownRecommendations.medianCooldown + " candles"
                  }
                />
              </div>
            </>
          )}
          <Table
            columns={columns}
            data={rows}
            renderRowSubCompontent={({ row }: any) => (
              <BacktestRowDetails
                backtest={row.original}
                optimizedMoneyManagement={optimizedMoneyManagement}
              />
            )}
          />
          
          {/* Bot Configuration Modal */}
          {selectedBacktest && (
            <BotConfigModal
              showModal={showBotConfigModal}
              mode="create"
              backtest={selectedBacktest}
              onClose={handleCloseBotConfigModal}
            />
          )}
        </>
      )}
    </>
  )
}

export default BacktestTable
