import {useQuery} from '@tanstack/react-query'
import React, {useEffect, useState} from 'react'
import {type SubmitHandler, useForm} from 'react-hook-form'

import useApiUrlStore from '../../../app/store/apiStore'
import {
    AccountClient,
    BacktestClient,
    BotType,
    DataClient,
    MoneyManagement,
    MoneyManagementClient,
    RunBacktestRequest,
    ScenarioClient,
    Ticker,
    Timeframe,
    TradingBotConfig,
} from '../../../generated/ManagingApi'
import type {BacktestModalProps, IBacktestsFormInput,} from '../../../global/type'
import {Loader, Slider} from '../../atoms'
import {Modal, Toast} from '../../mollecules'
import FormInput from '../../mollecules/FormInput/FormInput'
import CustomMoneyManagement from '../CustomMoneyManagement/CustomMoneyManagement'

const BacktestModal: React.FC<BacktestModalProps> = ({
  showModal,
  closeModal,
  setBacktests,
  showLoopSlider = false,
}) => {
  // Get date 15 days ago for start date
  const defaultStartDate = new Date();
  defaultStartDate.setDate(defaultStartDate.getDate() - 15);
  const defaultStartDateString = defaultStartDate.toISOString().split('T')[0];
  
  // Today for end date
  const defaultEndDate = new Date();
  const defaultEndDateString = defaultEndDate.toISOString().split('T')[0];

  const [startDate, setStartDate] = useState<string>(defaultStartDateString);
  const [endDate, setEndDate] = useState<string>(defaultEndDateString);

  const { register, handleSubmit, setValue } = useForm<IBacktestsFormInput>({
    defaultValues: {
      startDate: defaultStartDateString,
      endDate: defaultEndDateString,
      cooldownPeriod: 10, // Default cooldown period of 10 minutes
      maxLossStreak: 0, // Default max loss streak of 0 (no limit)
      maxPositionTimeHours: null, // Default to null (disabled)
      flipOnlyWhenInProfit: true, // Default to true
      balance: 10000, // Default balance
      closeEarlyWhenProfitable: false // Default to false
    }
  });
  const [selectedAccount, setSelectedAccount] = useState<string>('')
  const [selectedTimeframe, setSelectedTimeframe] = useState<Timeframe>(Timeframe.OneHour)
  const [selectedLoopQuantity, setLoopQuantity] = React.useState<number>(
    showLoopSlider ? 3 : 1
  )
  const [balance, setBalance] = useState<number>(10000)
  
  const [customMoneyManagement, setCustomMoneyManagement] =
    React.useState<MoneyManagement | undefined>(undefined)
  const [selectedMoneyManagement, setSelectedMoneyManagement] =
    useState<string>()
  const [showCustomMoneyManagement, setShowCustomMoneyManagement] =
    useState(false)

  const { apiUrl } = useApiUrlStore()

  const scenarioClient = new ScenarioClient({}, apiUrl)
  const accountClient = new AccountClient({}, apiUrl)
  const dataClient = new DataClient({}, apiUrl)
  const moneyManagementClient = new MoneyManagementClient({}, apiUrl)
  const backtestClient = new BacktestClient({}, apiUrl)

  const onSubmit: SubmitHandler<IBacktestsFormInput> = async (form) => {
    if (!form.scenarioName) {
      const t = new Toast('Please select a scenario', false);
      return;
    }

    if (!form.tickers || form.tickers.length === 0) {
      const t = new Toast('Please select at least one ticker', false);
      return;
    }

    // Process tickers sequentially
    for (const ticker of form.tickers) {
      const scenarioName = form.scenarioName;
      try {
        await runBacktest(form, ticker, scenarioName, customMoneyManagement, 0);
      } catch (error) {
        console.error(`Error running backtest for ${ticker}:`, error);
        // Continue with next ticker even if one fails
        continue;
      }
    }
  }

  async function runBacktest(
    form: IBacktestsFormInput,
    ticker: string,
    scenarioName: string,
    customMoneyManagement: MoneyManagement | undefined,
    loopCount: number
  ): Promise<void> {
    const t = new Toast(ticker + ' is running')
    
    console.log(customMoneyManagement)
    
    try {
      // Create the TradingBotConfig
      const tradingBotConfig: TradingBotConfig = {
        accountName: form.accountName,
        ticker: ticker as Ticker,
        scenarioName: scenarioName,
        timeframe: form.timeframe,
        botType: form.botType,
        isForWatchingOnly: false, // Always false for backtests
        isForBacktest: true, // Always true for backtests
        cooldownPeriod: form.cooldownPeriod || 1,
        maxLossStreak: form.maxLossStreak || 0,
        maxPositionTimeHours: form.maxPositionTimeHours || null,
        flipOnlyWhenInProfit: form.flipOnlyWhenInProfit ?? true,
        flipPosition: form.botType === BotType.FlippingBot, // Set based on bot type
        name: `Backtest-${scenarioName}-${ticker}-${new Date().toISOString()}`,
        botTradingBalance: form.balance,
        moneyManagement: customMoneyManagement || moneyManagements?.find(m => m.name === selectedMoneyManagement) || moneyManagements?.[0] || {
          name: 'placeholder',
          leverage: 1,
          stopLoss: 0.01,
          takeProfit: 0.02,
          timeframe: form.timeframe
        },
        closeEarlyWhenProfitable: form.closeEarlyWhenProfitable ?? false
      };

      // Create the RunBacktestRequest
      const request: RunBacktestRequest = {
        config: tradingBotConfig,
        startDate: new Date(form.startDate),
        endDate: new Date(form.endDate),
        balance: form.balance,
        watchOnly: false,
        save: form.save || false,
        moneyManagementName: customMoneyManagement ? undefined : selectedMoneyManagement,
        moneyManagement: customMoneyManagement
      };

      const backtest = await backtestClient.backtest_Run(request);
      
      t.update('success', `${backtest.config.ticker} Backtest Succeeded`)
      setBacktests((arr) => [...arr, backtest])

      if (showLoopSlider && selectedLoopQuantity > loopCount) {
        const nextCount = loopCount + 1
        const mm: MoneyManagement = {
          leverage: backtest.optimizedMoneyManagement.leverage,
          name: backtest.optimizedMoneyManagement.name + nextCount,
          stopLoss: backtest.optimizedMoneyManagement.stopLoss,
          takeProfit: backtest.optimizedMoneyManagement.takeProfit,
          timeframe: backtest.optimizedMoneyManagement.timeframe,
        }
        await runBacktest(form, ticker, scenarioName, mm, nextCount)
      }
    } catch (err) {
      t.update('error', 'Error: ' + err)
      throw err; // Re-throw the error to be caught by the caller
    }
  }

  function setSelectedAccountEvent(e: React.ChangeEvent<HTMLInputElement>) {
    setSelectedAccount(e.target.value)
  }

  function setSelectedTimeframeEvent(e: any) {
    setSelectedTimeframe(e.target.value)
  }

  function onMoneyManagementChange(e: any) {
    if (e.target.value === 'custom') {
      setShowCustomMoneyManagement(true)
      setCustomMoneyManagement(e.target.value)
    } else {
      setShowCustomMoneyManagement(false)
      setCustomMoneyManagement(undefined)
      setSelectedMoneyManagement(e.target.value)
    }
  }

  const { data: accounts } = useQuery({
    queryFn: () => accountClient.account_GetAccounts(),
    queryKey: ['accounts'],
  })

  const { data: scenarios } = useQuery({
    queryFn: () => scenarioClient.scenario_GetScenarios(),
    queryKey: ['scenarios'],
  })

  // Set the first scenario as default when scenarios are loaded
  useEffect(() => {
    if (scenarios && scenarios.length > 0 && scenarios[0].name) {
      setValue('scenarioName', scenarios[0].name);
    }
  }, [scenarios, setValue]);

  useEffect(() => {
    if (accounts && accounts.length > 0) {
      setSelectedAccount(accounts[0].name)
      setSelectedTimeframe(Timeframe.FiveMinutes)
    }
  }, [accounts])

  const { data: tickers, refetch: refetchTickers } = useQuery({
    enabled: !!selectedAccount && !!selectedTimeframe,
    queryFn: () => {
      if (selectedAccount && selectedTimeframe) {
        return dataClient.data_GetTickers(selectedTimeframe)
      }
    },
    queryKey: ['tickers', selectedAccount, selectedTimeframe],
  })

  const { data: moneyManagements } = useQuery({
    queryFn: async () => {
      return await moneyManagementClient.moneyManagement_GetMoneyManagements();
    },
    queryKey: ['moneyManagements'],
  })

  useEffect(() => {
    if (moneyManagements && moneyManagements.length > 0){
      setSelectedMoneyManagement(moneyManagements[0].name)
      setCustomMoneyManagement(undefined)
    }
  }, [moneyManagements])

  useEffect(() => {
    if (selectedAccount && selectedTimeframe) {
      refetchTickers()
    }
  }, [selectedAccount, selectedTimeframe])

  if (!accounts || !scenarios || !moneyManagements) {
    return <Loader></Loader>
  }

  return (
    <Modal
      showModal={showModal}
      onSubmit={handleSubmit(onSubmit)}
      onClose={closeModal}
      titleHeader="Run Backtest"
    >
      <div className="space-y-4">
        {/* First Row: Account & Timeframe */}
        <div className="grid grid-cols-2 gap-4">
          <FormInput label="Account" htmlFor="accountName">
            <select
              className="select select-bordered w-full"
              {...register('accountName', {
                onChange(e) {
                  setSelectedAccountEvent(e)
                },
              })}
            >
              <option value="" disabled>
                Select an account
              </option>
              {accounts.map((item) => (
                <option key={item.name} value={item.name}>
                  {item.name}
                </option>
              ))}
            </select>
          </FormInput>

          <FormInput label="Timeframe" htmlFor="timeframe">
            <select
              className="select select-bordered w-full"
              {...register('timeframe', {
                onChange(event) {
                  setSelectedTimeframeEvent(event)
                },
              })}
              value={selectedTimeframe}
            >
              {Object.keys(Timeframe).map((item) => (
                <option key={item} value={item}>
                  {item}
                </option>
              ))}
            </select>
          </FormInput>
        </div>

        {/* Second Row: Money Management & Bot Type */}
        <div className="grid grid-cols-2 gap-4">
          <FormInput label="Money Management" htmlFor="moneyManagement">
            <select
              className="select select-bordered w-full"
              {...register('moneyManagement', {
                onChange(event) {
                  onMoneyManagementChange(event)
                },
              })}
            >
              {moneyManagements.map((item) => (
                <option key={item.name} value={item.name}>
                  {item.name}
                </option>
              ))}
              <option key="custom" value="custom">
                Custom
              </option>
            </select>
          </FormInput>

          <FormInput label="Bot Type" htmlFor="botType">
            <select className="select select-bordered w-full" {...register('botType')}>
              {[BotType.ScalpingBot, BotType.FlippingBot].map((item) => (
                <option key={item} value={item}>
                  {item}
                </option>
              ))}
            </select>
          </FormInput>
        </div>

        {/* Losing streak info */}
        {(() => {
          // Find the selected money management object
          let mm: MoneyManagement | undefined = undefined;
          if (showCustomMoneyManagement && customMoneyManagement) {
            mm = { ...customMoneyManagement, stopLoss: customMoneyManagement.stopLoss / 100 };
          } else if (selectedMoneyManagement) {
            mm = moneyManagements.find((m) => m.name === selectedMoneyManagement);
          }
          // Use form balance if available, otherwise fall back to state balance
          const initialBalance = balance; // This state is kept in sync with form
          const minBalance = 10; // You can make this configurable if needed
          if (mm && mm.leverage && mm.stopLoss && initialBalance > minBalance) {
            const perLoss = mm.leverage * mm.stopLoss;
            if (perLoss > 0 && perLoss < 1) {
              const streak = Math.floor(Math.log(minBalance / initialBalance) / Math.log(1 - perLoss));
              return (
                <div className="text-sm text-info mt-1">
                  Max losing streak before balance drops below {minBalance}: <b>{streak}</b> trades (with leverage x{mm.leverage} and stop loss {Math.round(mm.stopLoss * 10000) / 100}% per trade, starting from {initialBalance})
                </div>
              );
            }
          }
          return null;
        })()}

        {showCustomMoneyManagement && (
          <div className="mt-6">
            <CustomMoneyManagement
              onCreateMoneyManagement={setCustomMoneyManagement}
              timeframe={selectedTimeframe || Timeframe.FiveMinutes}
              showCustomMoneyManagement={showCustomMoneyManagement}
            ></CustomMoneyManagement>
          </div>
        )}

        {/* Third Row: Scenario & Tickers (full width since they need more space) */}
        <div className="grid grid-cols-1 gap-4">
          <FormInput label="Scenario" htmlFor="scenarioName">
            <select
              className="select select-bordered w-full"
              {...register('scenarioName')}
            >
              <option value="" disabled>Select a scenario</option>
              {scenarios.map((item) => (
                <option key={item.name || 'unnamed'} value={item.name || ''}>
                  {item.name || 'Unnamed Scenario'}
                </option>
              ))}
            </select>
          </FormInput>

          <FormInput label="Tickers" htmlFor="tickers">
            <select
              className="select select-bordered w-full"
              multiple
              {...register('tickers')}
            >
              {tickers?.map((item) => (
                <option key={item.ticker} value={item.ticker}>
                  <img src={item.imageUrl || ''} alt={item.ticker} className="w-4 h-4 mr-2" />
                  {item.ticker}
                </option>
              ))}
            </select>
          </FormInput>
        </div>

        {/* Fourth Row: Balance & Cooldown Period */}
        <div className="grid grid-cols-2 gap-4">
          <FormInput label="Balance" htmlFor="balance">
            <input
              type="number"
              className="input input-bordered w-full"
              {...register('balance', { valueAsNumber: true })}
              onChange={(e) => {
                setValue('balance', Number(e.target.value));
                setBalance(Number(e.target.value)); // Keep state in sync for UI calculations
              }}
            />
          </FormInput>

          <FormInput label="Cooldown Period (candles)" htmlFor="cooldownPeriod">
            <input
              type="number"
              className="input input-bordered w-full"
              min="1"
              step="1"
              {...register('cooldownPeriod', { valueAsNumber: true })}
            />
          </FormInput>
        </div>

        {/* Fifth Row: Max Loss Streak & Max Position Time */}
        <div className="grid grid-cols-2 gap-4">
          <FormInput label="Max Loss Streak" htmlFor="maxLossStreak">
            <input
              type="number"
              className="input input-bordered w-full"
              min="0"
              step="1"
              {...register('maxLossStreak', { valueAsNumber: true })}
            />
          </FormInput>

          <FormInput label="Max Position Time (hours)" htmlFor="maxPositionTimeHours">
            <input
              type="number"
              className="input input-bordered w-full"
              min="0"
              step="0.5"
              placeholder="Leave empty to disable"
              {...register('maxPositionTimeHours', { valueAsNumber: true })}
            />
            <div className="text-xs text-gray-500 mt-1">
              Leave empty to disable time-based position closure
            </div>
          </FormInput>
        </div>

        {/* Sixth Row: Flip Only When In Profit & Close Early When Profitable */}
        <div className="grid grid-cols-2 gap-4">
          <FormInput label="Flip Only When In Profit" htmlFor="flipOnlyWhenInProfit">
            <input
              type="checkbox"
              className="toggle toggle-primary"
              {...register('flipOnlyWhenInProfit')}
            />
            <div className="text-xs text-gray-500 mt-1">
              If enabled, positions will only flip when current position is profitable
            </div>
          </FormInput>

          <FormInput label="Close Early When Profitable" htmlFor="closeEarlyWhenProfitable">
            <input
              type="checkbox"
              className="toggle toggle-primary"
              {...register('closeEarlyWhenProfitable')}
            />
            <div className="text-xs text-gray-500 mt-1">
              If enabled, positions will close early when they become profitable
            </div>
          </FormInput>
        </div>

        {/* Seventh Row: Save */}
        <div className="grid grid-cols-1 gap-4">
          <FormInput label="Save" htmlFor="save">
            <input
              type="checkbox"
              className="toggle toggle-primary"
              {...register('save')}
            />
          </FormInput>
        </div>

        {/* Eighth Row: Start Date & End Date */}
        <div className="grid grid-cols-2 gap-4">
          <FormInput label="Start Date" htmlFor="startDate">
            <input
              type="date"
              className="input input-bordered w-full"
              value={startDate}
              onChange={(e) => {
                setStartDate(e.target.value);
                setValue('startDate', e.target.value);
              }}
            />
          </FormInput>

          <FormInput label="End Date" htmlFor="endDate">
            <input
              type="date"
              className="input input-bordered w-full"
              value={endDate}
              onChange={(e) => {
                setEndDate(e.target.value);
                setValue('endDate', e.target.value);
              }}
            />
          </FormInput>
        </div>

        {/* Loop Slider (if enabled) */}
        {showLoopSlider && (
          <FormInput label="Loop" htmlFor="loop">
            <Slider
              id="loopSlider"
              min="1"
              max="10"
              value={selectedLoopQuantity.toString()}
              onChange={(e) => setLoopQuantity(Number(e.target.value))}
            ></Slider>
          </FormInput>
        )}
      </div>

      <div className="modal-action">
        <button type="submit" className="btn">
          Run
        </button>
      </div>
    </Modal>
  )
}

export default BacktestModal
