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,
    Backtest,
    BacktestClient,
    BotType,
    DataClient,
    MoneyManagement,
    MoneyManagementClient,
    ScenarioClient,
    Ticker,
    Timeframe,
} 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
    }
  });
  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;
    }

    for (const ticker of form.tickers) {
      const scenarioName = form.scenarioName;
      await runBacktest(form, ticker, scenarioName, customMoneyManagement, 0);
    }
  }

  async function runBacktest(
    form: IBacktestsFormInput,
    ticker: string,
    scenarioName: string,
    customMoneyManagement: MoneyManagement | undefined,
    loopCount: number
  ) {
    const t = new Toast(ticker + ' is running')
    // Use the name of the money management strategy if custom is not provided
    const moneyManagementName = customMoneyManagement ? undefined : selectedMoneyManagement
    
    console.log(customMoneyManagement)
    
    backtestClient
      .backtest_Run(
        form.accountName,
        form.botType,
        ticker as Ticker,
        scenarioName,
        form.timeframe,
        false, // watchOnly
        balance,
        moneyManagementName,
        new Date(form.startDate), // startDate
        new Date(form.endDate),   // endDate
        form.save,
        customMoneyManagement
      )
      .then((backtest: Backtest) => {
        t.update('success', `${backtest.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,
          }
          runBacktest(form, ticker, scenarioName, mm, nextCount)
        }
      })
      .catch((err) => {
        t.update('error', 'Error: ' + err)
      })
  }

  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">
        <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 w-full max-w-xs"
          {...register('timeframe', {
            onChange(event) {
              setSelectedTimeframeEvent(event)
            },
          })}
          value={selectedTimeframe}
        >
          {Object.keys(Timeframe).map((item) => (
            <option key={item} value={item}>
              {item}
            </option>
          ))}
        </select>
      </FormInput>

        <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>

        {/* 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 actual initial balance and a minimum threshold
          const initialBalance = balance;
          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>
      )}

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


        <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} value={item}>
                {item}
              </option>
            ))}
          </select>
        </FormInput>

        <div className="grid grid-cols-2 gap-4">
          <FormInput label="Balance" htmlFor="balance">
            <input
              type="number"
              className="input input-bordered w-full"
              value={balance}
              onChange={(e) => setBalance(Number(e.target.value))}
            />
          </FormInput>

          <FormInput label="Save" htmlFor="save">
            <input
              type="checkbox"
              className="toggle toggle-primary"
              {...register('save')}
            />
          </FormInput>
        </div>

        <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>

        {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
