import {ChevronDownIcon, ChevronRightIcon, EyeIcon, PlayIcon, TrashIcon} from '@heroicons/react/solid'
import React, {useEffect, useState} from 'react'
import {useQuery} from '@tanstack/react-query'

import useApiUrlStore from '../../../app/store/apiStore'
import type {Backtest, StartBotRequest, Ticker,} from '../../../generated/ManagingApi'
import {BacktestClient, BotClient, MoneyManagementClient} from '../../../generated/ManagingApi'
import type {IBacktestCards} from '../../../global/type'
import {CardText, SelectColumnFilter, Table, Toast} from '../../mollecules'
import BotNameModal from '../../mollecules/Modal/BotNameModal'

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 [showBotNameModal, setShowBotNameModal] = useState(false)
  const [isForWatchOnly, setIsForWatchOnly] = useState(false)
  const [currentBacktest, setCurrentBacktest] = useState<Backtest | null>(null)
  const [selectedMoneyManagement, setSelectedMoneyManagement] = useState<string>('')

  // Fetch money managements
  const { data: moneyManagements } = useQuery({
    queryFn: async () => {
      const moneyManagementClient = new MoneyManagementClient({}, apiUrl)
      return await moneyManagementClient.moneyManagement_GetMoneyManagements()
    },
    queryKey: ['moneyManagements'],
  })

  // Set the first money management as default when the data is loaded
  useEffect(() => {
    if (moneyManagements && moneyManagements.length > 0) {
      setSelectedMoneyManagement(moneyManagements[0].name)
    }
  }, [moneyManagements])

  async function runBot(botName: string, backtest: Backtest, isForWatchOnly: boolean, moneyManagementName: string, initialTradingBalance: number) {
    const t = new Toast('Bot is starting')
    const client = new BotClient({}, apiUrl)

    // Check if the money management name is "custom" or contains "custom"
    const isCustomMoneyManagement = 
      !moneyManagementName || 
      moneyManagementName.toLowerCase() === 'custom' || 
      moneyManagementName.toLowerCase().includes('custom');
    
    const request: StartBotRequest = {
      accountName: backtest.accountName,
      botName: botName,
      botType: backtest.botType,
      isForWatchOnly: isForWatchOnly,
      // Only use the money management name if it's not a custom money management
      moneyManagementName: isCustomMoneyManagement ? '' : moneyManagementName,
      scenario: backtest.scenario,
      ticker: backtest.ticker as Ticker,
      timeframe: backtest.timeframe,
      initialTradingBalance: initialTradingBalance,
    }

    await client
      .bot_Start(request)
      .then((botStatus: string) => {
        t.update('info', 'Bot status: ' + botStatus)
      })
      .catch((err) => {
        t.update('error', 'Error: ' + err)
      })
  }

  const handleOpenBotNameModal = (backtest: Backtest, isForWatchOnly: boolean) => {
    setCurrentBacktest(backtest)
    setIsForWatchOnly(isForWatchOnly)
    setShowBotNameModal(true)
  }

  const handleCloseBotNameModal = () => {
    setShowBotNameModal(false)
  }

  const handleSubmitBotName = (botName: string, backtest: Backtest, isForWatchOnly: boolean, moneyManagementName: string, initialTradingBalance: number) => {
    runBot(botName, backtest, isForWatchOnly, moneyManagementName, initialTradingBalance)
    setShowBotNameModal(false)
  }

  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: 'ticker',
            disableSortBy: true,
          },
         
          {
            Filter: SelectColumnFilter,
            Header: 'Timeframe',
            accessor: 'timeframe',
            disableSortBy: true,
          },
          {
            Filter: SelectColumnFilter,
            Header: 'Scenario',
            accessor: 'scenario',
            disableSortBy: true,
          },
          {
            Filter: SelectColumnFilter,
            Header: 'BotType',
            accessor: '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="Run in watch-only mode">
                  <button
                    data-value={cell.row.values.name}
                    onClick={() => handleOpenBotNameModal(cell.row.original as Backtest, true)}
                  >
                    <EyeIcon className="text-primary w-4"></EyeIcon>
                  </button>
                </div>
              </>
            ),
            Header: '',
            accessor: 'watcher',
            disableFilters: true,
          },
          {
            Cell: ({ cell }: any) => (
              <>
                <div className="tooltip" data-tip="Run bot">
                  <button
                    data-value={cell.row.values.name}
                    onClick={() => handleOpenBotNameModal(cell.row.original as Backtest, false)}
                  >
                    <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,
        });
      }
    }
  }, [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>
          )}
          <Table
            columns={columns}
            data={rows}
            renderRowSubCompontent={({ row }: any) => (
              <BacktestRowDetails
                backtest={row.original}
                optimizedMoneyManagement={optimizedMoneyManagement}
              />
            )}
          />
          {showBotNameModal && currentBacktest && moneyManagements && (
            <BotNameModal
              showModal={showBotNameModal}
              onClose={handleCloseBotNameModal}
              backtest={currentBacktest}
              isForWatchOnly={isForWatchOnly}
              onSubmitBotName={(botName, backtest, isForWatchOnly, moneyManagementName, initialTradingBalance) => 
                handleSubmitBotName(botName, backtest, isForWatchOnly, moneyManagementName, initialTradingBalance)
              }
              moneyManagements={moneyManagements}
              selectedMoneyManagement={selectedMoneyManagement}
              setSelectedMoneyManagement={setSelectedMoneyManagement}
            />
          )}
        </>
      )}
    </>
  )
}

export default BacktestTable
