import React, {useState} from 'react'
import type {SubmitHandler} from 'react-hook-form'
import {useForm} from 'react-hook-form'
import {Account, AccountClient, Ticker,} from '../../../generated/ManagingApi'
import Modal from '../../../components/mollecules/Modal/Modal'
import useApiUrlStore from '../../../app/store/apiStore'
import {FormInput, Toast} from '../../../components/mollecules'
import {useApiError} from '../../../hooks/useApiError'

interface SwapModalProps {
    isOpen: boolean
    onClose: () => void
    account: Account
    fromTicker: Ticker
    availableAmount: number
}

interface SwapFormInput {
    fromTicker: Ticker
    toTicker: Ticker
    amount: number
    orderType: string
    triggerRatio?: number
    allowedSlippage: number
}

interface ValidationErrorResponse {
    type: string
    title: string
    status: number
    errors: Record<string, string[]>
    traceId: string
}

const SwapModal: React.FC<SwapModalProps> = ({
                                                 isOpen,
                                                 onClose,
                                                 account,
                                                 fromTicker,
                                                 availableAmount,
                                             }) => {
    const [isLoading, setIsLoading] = useState(false)
    const [validationErrors, setValidationErrors] = useState<Record<string, string[]>>({})
    const {error, setError, handleApiErrorWithToast} = useApiError()
    const {apiUrl} = useApiUrlStore()
    const client = new AccountClient({}, apiUrl)
    const [selectedToTicker, setSelectedToTicker] = useState<Ticker>(Ticker.USDC)
    const [selectedOrderType, setSelectedOrderType] = useState<string>('market')

    const {register, handleSubmit, watch, setValue} = useForm<SwapFormInput>({
        defaultValues: {
            fromTicker: fromTicker,
            toTicker: Ticker.USDC,
            amount: availableAmount * 0.1, // Start with 10% of available amount
            orderType: 'market',
            allowedSlippage: 0.5,
        }
    })

    const watchedAmount = watch('amount')

    function setSelectedToTickerEvent(e: React.ChangeEvent<HTMLSelectElement>) {
        setSelectedToTicker(e.target.value as Ticker)
    }

    function setSelectedOrderTypeEvent(e: React.ChangeEvent<HTMLSelectElement>) {
        setSelectedOrderType(e.target.value)
    }

    const onSubmit: SubmitHandler<SwapFormInput> = async (form) => {
        const t = new Toast(`Swapping ${form.amount} ${form.fromTicker} to ${form.toTicker} on ${account.name}`)
        setIsLoading(true)
        setError(null)
        setValidationErrors({})

        try {
            const result = await client.account_SwapGmxTokens(
                account.name,
                {
                    fromTicker: form.fromTicker,
                    toTicker: form.toTicker,
                    amount: form.amount,
                    orderType: form.orderType,
                    triggerRatio: form.triggerRatio,
                    allowedSlippage: form.allowedSlippage,
                }
            )

            if (result.success) {
                t.update('success', `Swap successful! Hash: ${result.hash}`)
                onClose()
            } else {
                console.log(result)
                const errorMessage = result.error || result.message || 'Swap failed'
                setError(errorMessage)
                t.update('error', `Swap failed: ${errorMessage}`)
            }
        } catch (err: any) {
            // Handle validation errors from API
            if (err.response?.data && typeof err.response.data === 'object') {
                const errorData = err.response.data as ValidationErrorResponse
                console.log(errorData)
                if (errorData.errors && typeof errorData.errors === 'object') {
                    setValidationErrors(errorData.errors)
                    const errorMessages = Object.values(errorData.errors).flat()
                    const errorMessage = errorMessages.join(', ')
                    setError(errorMessage)
                    t.update('error', `Validation failed: ${errorMessage}`)
                } else {
                    handleApiErrorWithToast(err, t)
                }
            } else {
                handleApiErrorWithToast(err, t)
            }
        } finally {
            setIsLoading(false)
        }
    }

    const handleFormSubmit = async (e: React.FormEvent) => {
        e.preventDefault()
        await handleSubmit(onSubmit)(e)
    }

    const modalContent = (
        <>
            {isLoading ? (
                <div className="text-center py-4">
                    <span className="loading loading-spinner loading-md"></span>
                    <p>Processing swap...</p>
                </div>
            ) : error ? (
                <div className="alert alert-error mb-4">
                    <p>{error}</p>
                </div>
            ) : (
                <>
                    <div className="mb-4">
                        <p className="mb-2">
                            <strong>Account:</strong> {account.name}
                        </p>
                        <p className="mb-2">
                            <strong>From:</strong> {fromTicker}
                        </p>
                    </div>

                    <form onSubmit={handleFormSubmit}>
                        {Object.keys(validationErrors).length > 0 && (
                            <div className="alert alert-error mb-4">
                                <div>
                                    <h4 className="font-bold">Validation Errors:</h4>
                                    {Object.entries(validationErrors).map(([field, errors]) => (
                                        <div key={field} className="mt-1">
                                            <strong>{field}:</strong> {errors.join(', ')}
                                        </div>
                                    ))}
                                </div>
                            </div>
                        )}
                        <div className="space-y-4 mb-4">
                            <FormInput label="To Ticker" htmlFor="toTicker">
                                <select
                                    className="select select-bordered w-full"
                                    {...register('toTicker', {
                                        onChange(e) {
                                            setSelectedToTickerEvent(e)
                                        },
                                        value: selectedToTicker,
                                    })}
                                >
                                    {Object.values(Ticker)
                                        .filter(ticker => ticker !== fromTicker) // Exclude the from ticker
                                        .map((ticker) => (
                                            <option key={ticker} value={ticker}>
                                                {ticker}
                                            </option>
                                        ))}
                                </select>
                            </FormInput>

                            <FormInput label="Amount" htmlFor="amount">
                                <div className="w-full">
                                    <input
                                        type="number"
                                        step="any"
                                        placeholder="Enter amount to swap"
                                        className={`input input-bordered w-full mb-2 ${validationErrors.Amount ? 'input-error' : ''}`}
                                        {...register('amount', {
                                            valueAsNumber: true,
                                            min: 0.00000000000001,
                                            max: availableAmount,
                                            required: true
                                        })}
                                    />
                                    {validationErrors.Amount && (
                                        <div className="text-error text-xs mt-1">
                                            {validationErrors.Amount.map((error, index) => (
                                                <div key={index}>{error}</div>
                                            ))}
                                        </div>
                                    )}
                                    <div className="w-full">
                                        <input
                                            type="range"
                                            min="0"
                                            max={availableAmount}
                                            step={0.00000000000001}
                                            className="range range-primary w-full"
                                            value={watchedAmount || 0}
                                            onChange={(e) => {
                                                const value = parseFloat(e.target.value)
                                                setValue('amount', value)
                                            }}
                                        />

                                        <div className="text-center text-xs text-gray-500 mt-1">
                                            {watchedAmount && availableAmount > 0 ? (
                                                <span>{((watchedAmount / availableAmount) * 100).toFixed(1)}% of available balance</span>
                                            ) : (
                                                <span>0% of available balance</span>
                                            )}
                                        </div>
                                    </div>
                                </div>
                            </FormInput>

                            <FormInput label="Order Type" htmlFor="orderType">
                                <select
                                    className="select select-bordered w-full"
                                    {...register('orderType', {
                                        onChange(e) {
                                            setSelectedOrderTypeEvent(e)
                                        },
                                        value: selectedOrderType,
                                    })}
                                >
                                    <option value="market">Market</option>
                                    <option value="limit">Limit</option>
                                    <option value="stop">Stop</option>
                                </select>
                            </FormInput>

                            <FormInput label="Allowed Slippage (%)" htmlFor="allowedSlippage">
                                <input
                                    type="number"
                                    step="0.1"
                                    placeholder="0.5"
                                    className={`input input-bordered w-full ${validationErrors.AllowedSlippage ? 'input-error' : ''}`}
                                    {...register('allowedSlippage', {
                                        valueAsNumber: true,
                                        min: 0.1,
                                        max: 10,
                                        value: 0.5
                                    })}
                                />
                                {validationErrors.AllowedSlippage && (
                                    <div className="text-error text-xs mt-1">
                                        {validationErrors.AllowedSlippage.map((error, index) => (
                                            <div key={index}>{error}</div>
                                        ))}
                                    </div>
                                )}
                            </FormInput>

                            {selectedOrderType === 'limit' && (
                                <FormInput label="Trigger Ratio" htmlFor="triggerRatio">
                                    <input
                                        type="number"
                                        step="any"
                                        placeholder="Enter trigger ratio"
                                        className={`input input-bordered w-full ${validationErrors.TriggerRatio ? 'input-error' : ''}`}
                                        {...register('triggerRatio', {valueAsNumber: true})}
                                    />
                                    {validationErrors.TriggerRatio && (
                                        <div className="text-error text-xs mt-1">
                                            {validationErrors.TriggerRatio.map((error, index) => (
                                                <div key={index}>{error}</div>
                                            ))}
                                        </div>
                                    )}
                                </FormInput>
                            )}

                            <button
                                type="submit"
                                className="btn btn-primary w-full mt-2"
                                disabled={isLoading || !watchedAmount || watchedAmount <= 0}
                            >
                                {isLoading ? (
                                    <span className="loading loading-spinner"></span>
                                ) : (
                                    `Swap ${watchedAmount || 0} ${fromTicker} to ${selectedToTicker}`
                                )}
                            </button>
                        </div>
                    </form>

                    <div className="mt-4">
                        <div className="alert alert-info">
                            <p className="text-sm">
                                <strong>Note:</strong> Ensure account has sufficient balance for the swap.
                            </p>
                        </div>
                    </div>
                </>
            )}
        </>
    )

    return (
        <Modal
            showModal={isOpen}
            onClose={onClose}
            titleHeader="Swap Tokens on GMX"
        >
            {modalContent}
        </Modal>
    )
}

export default SwapModal 