/**
 * Trustless bridge (Chain 138 <-> Ethereum): Lockbox deposit, claim status, bridgeAndSwap with router choice.
 */

import { useState } from 'react';
import { useAccount, useChainId, useSwitchChain } from 'wagmi';
import { useReadContract, useWriteContract, useWaitForTransactionReceipt } from 'wagmi';
import { padHex, toHex } from 'viem';
import toast from 'react-hot-toast';
import {
  TRUSTLESS,
  LOCKBOX_138_ABI,
  DUAL_ROUTER_COORDINATOR_ABI,
  CHALLENGE_MANAGER_ABI,
  ERC20_ABI,
} from '../../config/bridge';
import { getTrustlessL2LockboxConfig, TRUSTLESS_L2_CHAIN_ID } from '../../config/trustlessL2';

const MAINNET_CHAIN_ID = 1;
const OUTPUT_ASSET_ETH = 0;
const OUTPUT_ASSET_WETH = 1;
const ZERO = '0x0000000000000000000000000000000000000000' as const;

const STABLECOIN_OPTIONS = [
  { value: 'USDT', label: 'USDT', address: TRUSTLESS.mainnet.USDT },
  { value: 'USDC', label: 'USDC', address: TRUSTLESS.mainnet.USDC },
  { value: 'DAI', label: 'DAI', address: TRUSTLESS.mainnet.DAI },
] as const;

export default function TrustlessBridgeForm() {
  const l2 = getTrustlessL2LockboxConfig();
  const nativeSymbol = l2.viemChain.nativeCurrency.symbol;
  const l2Label = l2.viemChain.name;

  const LOCKBOX_ERC20_OPTIONS = [
    { value: 'WETH', label: 'WETH', address: l2.weth, decimals: 18 },
    { value: 'cUSDT', label: 'cUSDT', address: l2.cusdt, decimals: 6 },
    { value: 'cUSDC', label: 'cUSDC', address: l2.cusdc, decimals: 6 },
  ].filter((o) => o.address !== ZERO) as Array<{ value: string; label: string; address: `0x${string}`; decimals: number }>;
  const { address } = useAccount();
  const chainId = useChainId();
  const switchChain = useSwitchChain();

  const [depositId, setDepositId] = useState('');
  const [recipient, setRecipient] = useState(address || '');
  const [amount, setAmount] = useState('');
  const [depositType, setDepositType] = useState<'native' | 'erc20'>('native');
  const [erc20Token, setErc20Token] = useState(LOCKBOX_ERC20_OPTIONS[0]?.value ?? 'WETH');
  const [outputAsset, setOutputAsset] = useState<0 | 1>(OUTPUT_ASSET_WETH);
  const [stablecoin, setStablecoin] = useState<typeof STABLECOIN_OPTIONS[number]['value']>('USDT');
  const [amountOutMin, setAmountOutMin] = useState('');
  const [useEnhancedRouter, setUseEnhancedRouter] = useState(true);
  const [checkDepositId, setCheckDepositId] = useState('');
  const [finalizeDepositId, setFinalizeDepositId] = useState('');

  const lockboxAddress = l2.lockbox;
  const coordinatorAddress = TRUSTLESS.mainnet.DUAL_ROUTER_BRIDGE_SWAP_COORDINATOR;
  const challengeManagerAddress = TRUSTLESS.mainnet.CHALLENGE_MANAGER;
  const erc20TokenAddress = LOCKBOX_ERC20_OPTIONS.find((o) => o.value === erc20Token)?.address ?? l2.weth;

  const { data: nonceData } = useReadContract({
    address: address ? lockboxAddress : undefined,
    abi: LOCKBOX_138_ABI,
    functionName: 'getNonce',
    args: address ? [address] : undefined,
    chainId: l2.chainId,
  });

  const { data: canSwapResult, refetch: refetchCanSwap } = useReadContract({
    address: checkDepositId ? coordinatorAddress : undefined,
    abi: DUAL_ROUTER_COORDINATOR_ABI,
    functionName: 'canSwap',
    args: checkDepositId ? [BigInt(checkDepositId)] : undefined,
    chainId: MAINNET_CHAIN_ID,
  });

  const { data: canFinalizeResult, refetch: refetchCanFinalize } = useReadContract({
    address: finalizeDepositId ? challengeManagerAddress : undefined,
    abi: CHALLENGE_MANAGER_ABI,
    functionName: 'canFinalize',
    args: finalizeDepositId ? [BigInt(finalizeDepositId)] : undefined,
    chainId: MAINNET_CHAIN_ID,
  });

  const { data: tokenAllowance } = useReadContract({
    address: depositType === 'erc20' && address ? erc20TokenAddress : undefined,
    abi: ERC20_ABI,
    functionName: 'allowance',
    args: address ? [address, lockboxAddress] : undefined,
    chainId: l2.chainId,
  });

  const { writeContract, data: hash, isPending, reset } = useWriteContract();
  const { isLoading: isConfirming, isSuccess } = useWaitForTransactionReceipt({ hash });

  const onL2 = chainId === l2.chainId;
  const onMainnet = chainId === MAINNET_CHAIN_ID;
  const l2Misconfigured =
    TRUSTLESS_L2_CHAIN_ID === 2138 && l2.chainId === 138;

  const stablecoinAddress = STABLECOIN_OPTIONS.find((o) => o.value === stablecoin)?.address ?? TRUSTLESS.mainnet.USDT;

  const handleDepositNative = () => {
    if (!address || !recipient || !amount) {
      toast.error('Connect wallet and enter recipient and amount');
      return;
    }
    const wei = BigInt(Math.floor(parseFloat(amount) * 1e18));
    if (wei <= 0n) {
      toast.error('Amount must be > 0');
      return;
    }
    const nonceBytes = padHex(toHex(nonceData ?? 0n), { size: 32 }) as `0x${string}`;
    if (!onL2) {
      switchChain?.switchChain({ chainId: l2.chainId });
      return;
    }
    writeContract(
      {
        address: lockboxAddress,
        abi: LOCKBOX_138_ABI,
        functionName: 'depositNative',
        args: [recipient as `0x${string}`, nonceBytes],
        value: wei,
      },
      {
        onSuccess: () => toast.success('Deposit submitted. Switch to Mainnet to check claim and run Bridge & Swap.'),
        onError: (e) => toast.error(e?.message ?? 'Deposit failed'),
      }
    );
  };

  const erc20Decimals = LOCKBOX_ERC20_OPTIONS.find((o) => o.value === erc20Token)?.decimals ?? 18;
  const erc20AmountWei = (() => {
    if (!amount) return 0n;
    const d = erc20Decimals;
    const [whole = '0', frac = ''] = amount.split('.');
    const fracPadded = frac.slice(0, d).padEnd(d, '0');
    return BigInt(whole) * 10n ** BigInt(d) + BigInt(fracPadded || '0');
  })();

  const handleApprove = () => {
    if (!address || !amount || depositType !== 'erc20') return;
    if (erc20AmountWei <= 0n) {
      toast.error('Amount must be > 0');
      return;
    }
    if (!onL2) {
      switchChain?.switchChain({ chainId: l2.chainId });
      return;
    }
    writeContract(
      {
        address: erc20TokenAddress,
        abi: ERC20_ABI,
        functionName: 'approve',
        args: [lockboxAddress, erc20AmountWei],
      },
      {
        onSuccess: () => toast.success('Approval submitted'),
        onError: (e) => toast.error(e?.message ?? 'Approval failed'),
      }
    );
  };

  const handleDepositERC20 = () => {
    if (!address || !recipient || !amount) {
      toast.error('Connect wallet and enter recipient and amount');
      return;
    }
    if (erc20AmountWei <= 0n) {
      toast.error('Amount must be > 0');
      return;
    }
    const nonceBytes = padHex(toHex(nonceData ?? 0n), { size: 32 }) as `0x${string}`;
    if (!onL2) {
      switchChain?.switchChain({ chainId: l2.chainId });
      return;
    }
    writeContract(
      {
        address: lockboxAddress,
        abi: LOCKBOX_138_ABI,
        functionName: 'depositERC20',
        args: [erc20TokenAddress, erc20AmountWei, recipient as `0x${string}`, nonceBytes],
      },
      {
        onSuccess: () => toast.success('ERC-20 deposit submitted. Switch to Mainnet to finalize claim and run Bridge & Swap.'),
        onError: (e) => toast.error(e?.message ?? 'Deposit failed'),
      }
    );
  };

  const handleFinalizeClaim = () => {
    if (!finalizeDepositId || !onMainnet) {
      if (!onMainnet) switchChain?.switchChain({ chainId: MAINNET_CHAIN_ID });
      return;
    }
    writeContract(
      {
        address: challengeManagerAddress,
        abi: CHALLENGE_MANAGER_ABI,
        functionName: 'finalizeClaim',
        args: [BigInt(finalizeDepositId)],
      },
      {
        onSuccess: () => toast.success('Claim finalized'),
        onError: (e) => toast.error(e?.message ?? 'Finalize failed'),
      }
    );
  };

  const handleBridgeAndSwap = () => {
    if (!depositId || !recipient || !amountOutMin) {
      toast.error('Enter deposit ID, recipient, and minimum out');
      return;
    }
    if (!onMainnet) {
      switchChain?.switchChain({ chainId: MAINNET_CHAIN_ID });
      return;
    }
    const minOut = BigInt(amountOutMin);
    const routeData = '0x' as `0x${string}`;
    writeContract(
      {
        address: coordinatorAddress,
        abi: DUAL_ROUTER_COORDINATOR_ABI,
        functionName: 'bridgeAndSwap',
        args: [
          BigInt(depositId),
          recipient as `0x${string}`,
          outputAsset,
          stablecoinAddress,
          minOut,
          routeData,
          useEnhancedRouter,
        ],
        value: outputAsset === OUTPUT_ASSET_ETH ? undefined : 0n,
      },
      {
        onSuccess: () => toast.success('Bridge & Swap submitted'),
        onError: (e) => toast.error(e?.message ?? 'Bridge & Swap failed'),
      }
    );
  };

  if (isSuccess && hash) {
    toast.success('Transaction confirmed');
    reset();
  }

  return (
    <div className="space-y-8 rounded-2xl bg-white/5 backdrop-blur border border-cyan-400/20 p-6">
      <h2 className="text-2xl font-bold text-white">Trustless Bridge ({l2Label} ↔ Mainnet)</h2>
      {l2Misconfigured && (
        <p className="text-amber-200/90 text-sm mb-2 rounded-lg border border-amber-400/40 bg-amber-500/10 p-3">
          VITE_TRUSTLESS_L2_CHAIN_ID is 2138 but VITE_ENABLE_CHAIN2138 is off — L2 fell back to {l2Label}. Enable the testnet chain or set L2 to 138.
        </p>
      )}
      {l2.chainId === 2138 && lockboxAddress === ZERO && (
        <p className="text-amber-200/90 text-sm mb-2 rounded-lg border border-amber-400/40 bg-amber-500/10 p-3">
          Set VITE_LOCKBOX_2138 (and token addresses) after deploying the testnet lockbox.
        </p>
      )}

      {/* Lockbox L2 deposit */}
      <section>
        <h3 className="text-lg font-semibold text-cyan-300 mb-3">1. Deposit on {l2Label} (Lockbox)</h3>
        <p className="text-white/70 text-sm mb-3">
          Deposit native {nativeSymbol} or ERC-20 (WETH, cUSDT, cUSDC) on {l2Label}. Then relay and finalize claim on Mainnet before Bridge & Swap.
        </p>
        {!onL2 && (
          <button
            type="button"
            onClick={() => switchChain?.switchChain({ chainId: l2.chainId })}
            className="mb-3 px-4 py-2 rounded-lg bg-cyan-500/20 text-cyan-300 border border-cyan-400/40"
          >
            Switch to {l2Label}
          </button>
        )}
        <div className="grid gap-3 max-w-md">
          <div className="flex gap-4 items-center">
            <span className="text-white/80">Deposit type:</span>
            <label className="flex items-center gap-2 cursor-pointer">
              <input type="radio" checked={depositType === 'native'} onChange={() => setDepositType('native')} className="rounded" />
              <span>Native {nativeSymbol}</span>
            </label>
            <label className="flex items-center gap-2 cursor-pointer">
              <input type="radio" checked={depositType === 'erc20'} onChange={() => setDepositType('erc20')} className="rounded" />
              <span>ERC-20</span>
            </label>
          </div>
          {depositType === 'erc20' && LOCKBOX_ERC20_OPTIONS.length === 0 && (
            <p className="text-amber-200/90 text-sm">No ERC-20 tokens configured for this L2 (set non-zero addresses in env).</p>
          )}
          {depositType === 'erc20' && LOCKBOX_ERC20_OPTIONS.length > 0 && (
            <div className="flex gap-4 items-center">
              <label htmlFor="trustless-bridge-token" className="text-white/80">Token:</label>
              <select
                id="trustless-bridge-token"
                name="erc20Token"
                value={erc20Token}
                onChange={(e) => setErc20Token(e.target.value)}
                className="px-3 py-2 rounded-lg bg-white/10 text-white border border-cyan-400/30"
              >
                {LOCKBOX_ERC20_OPTIONS.map((o) => (
                  <option key={o.value} value={o.value}>{o.label}</option>
                ))}
              </select>
            </div>
          )}
          <label htmlFor="trustless-bridge-recipient" className="sr-only">Recipient (Mainnet address)</label>
          <input
            id="trustless-bridge-recipient"
            name="recipient"
            type="text"
            placeholder="Recipient (Mainnet address)"
            value={recipient}
            onChange={(e) => setRecipient(e.target.value)}
            className="w-full px-3 py-2 rounded-lg bg-white/10 text-white border border-cyan-400/30"
          />
          <label htmlFor="trustless-bridge-amount" className="sr-only">Amount</label>
          <input
            id="trustless-bridge-amount"
            name="amount"
            type="text"
            placeholder={depositType === 'native' ? `Amount (${nativeSymbol})` : 'Amount (token units)'}
            value={amount}
            onChange={(e) => setAmount(e.target.value)}
            className="w-full px-3 py-2 rounded-lg bg-white/10 text-white border border-cyan-400/30"
          />
          {depositType === 'native' && (
            <button
              type="button"
              disabled={isPending || isConfirming || !address || !amount || !recipient || !onL2 || lockboxAddress === ZERO}
              onClick={handleDepositNative}
              className="px-4 py-2 rounded-lg bg-cyan-500 text-white font-medium disabled:opacity-50"
            >
              {isPending || isConfirming ? 'Confirming...' : `Deposit native ${nativeSymbol}`}
            </button>
          )}
          {depositType === 'erc20' && (
            <>
              {tokenAllowance !== undefined && BigInt(amount || 0) * 10n ** 18n > (tokenAllowance ?? 0n) && (
                <button
                  type="button"
                  disabled={isPending || isConfirming || !address || !amount || !onL2 || lockboxAddress === ZERO}
                  onClick={handleApprove}
                  className="px-4 py-2 rounded-lg bg-cyan-500/80 text-white font-medium disabled:opacity-50"
                >
                  {isPending || isConfirming ? 'Confirming...' : 'Approve Lockbox'}
                </button>
              )}
              <button
                type="button"
                disabled={isPending || isConfirming || !address || !amount || !recipient || !onL2 || lockboxAddress === ZERO || (tokenAllowance !== undefined && erc20AmountWei > (tokenAllowance ?? 0n))}
                onClick={handleDepositERC20}
                className="px-4 py-2 rounded-lg bg-cyan-500 text-white font-medium disabled:opacity-50"
              >
                {isPending || isConfirming ? 'Confirming...' : 'Deposit ERC-20'}
              </button>
            </>
          )}
        </div>
      </section>

      {/* Claim status / canSwap */}
      <section>
        <h3 className="text-lg font-semibold text-cyan-300 mb-3">2. Check if claim is ready (Mainnet)</h3>
        <p className="text-white/70 text-sm mb-3">After claim is finalized on Mainnet, you can run Bridge & Swap.</p>
        {!onMainnet && (
          <button
            type="button"
            onClick={() => switchChain?.switchChain({ chainId: MAINNET_CHAIN_ID })}
            className="mb-3 px-4 py-2 rounded-lg bg-cyan-500/20 text-cyan-300 border border-cyan-400/40"
          >
            Switch to Ethereum Mainnet
          </button>
        )}
        <div className="flex gap-3 items-end flex-wrap">
          <div>
            <label className="block text-white/70 text-sm mb-1">Deposit ID</label>
            <input
              type="text"
              placeholder="Deposit ID"
              value={checkDepositId}
              onChange={(e) => setCheckDepositId(e.target.value)}
              className="w-40 px-3 py-2 rounded-lg bg-white/10 text-white border border-cyan-400/30"
            />
          </div>
          <button
            type="button"
            onClick={() => refetchCanSwap()}
            className="px-4 py-2 rounded-lg bg-white/10 text-white border border-cyan-400/40"
          >
            Check canSwap
          </button>
        </div>
        {checkDepositId && canSwapResult !== undefined && (
          <p className="mt-2 text-white/90">
            Can swap: {Array.isArray(canSwapResult) ? String(canSwapResult[0]) : String(canSwapResult)} 
            {Array.isArray(canSwapResult) && canSwapResult[1] ? ` — ${canSwapResult[1]}` : ''}
          </p>
        )}
      </section>

      {/* Finalize claim (Mainnet) */}
      <section>
        <h3 className="text-lg font-semibold text-cyan-300 mb-3">2b. Finalize claim (Mainnet)</h3>
        <p className="text-white/70 text-sm mb-3">After the challenge window expires, anyone can finalize the claim so the recipient can run Bridge & Swap.</p>
        {!onMainnet && (
          <button
            type="button"
            onClick={() => switchChain?.switchChain({ chainId: MAINNET_CHAIN_ID })}
            className="mb-3 px-4 py-2 rounded-lg bg-cyan-500/20 text-cyan-300 border border-cyan-400/40"
          >
            Switch to Ethereum Mainnet
          </button>
        )}
        <div className="flex gap-3 items-end flex-wrap">
          <div>
            <label className="block text-white/70 text-sm mb-1">Deposit ID</label>
            <input
              type="text"
              placeholder="Deposit ID"
              value={finalizeDepositId}
              onChange={(e) => setFinalizeDepositId(e.target.value)}
              className="w-40 px-3 py-2 rounded-lg bg-white/10 text-white border border-cyan-400/30"
            />
          </div>
          <button type="button" onClick={() => refetchCanFinalize()} className="px-4 py-2 rounded-lg bg-white/10 text-white border border-cyan-400/40">Check canFinalize</button>
          <button
            type="button"
            disabled={isPending || isConfirming || !finalizeDepositId || !onMainnet}
            onClick={handleFinalizeClaim}
            className="px-4 py-2 rounded-lg bg-cyan-500 text-white font-medium disabled:opacity-50"
          >
            {isPending || isConfirming ? 'Confirming...' : 'Finalize claim'}
          </button>
        </div>
        {finalizeDepositId && canFinalizeResult !== undefined && (
          <p className="mt-2 text-white/90">
            Can finalize: {Array.isArray(canFinalizeResult) ? String(canFinalizeResult[0]) : String(canFinalizeResult)}
            {Array.isArray(canFinalizeResult) && canFinalizeResult[1] ? ` — ${canFinalizeResult[1]}` : ''}
          </p>
        )}
      </section>

      {/* Bridge and swap with router choice */}
      <section>
        <h3 className="text-lg font-semibold text-cyan-300 mb-3">3. Bridge and swap (Mainnet)</h3>
        <p className="text-white/70 text-sm mb-3">Uses DualRouter coordinator: choose basic (SwapRouter) or enhanced (EnhancedSwapRouter) router.</p>
        {!onMainnet && (
          <button
            type="button"
            onClick={() => switchChain?.switchChain({ chainId: MAINNET_CHAIN_ID })}
            className="mb-3 px-4 py-2 rounded-lg bg-cyan-500/20 text-cyan-300 border border-cyan-400/40"
          >
            Switch to Ethereum Mainnet
          </button>
        )}
        <div className="grid gap-3 max-w-md">
          <input
            type="text"
            placeholder="Deposit ID"
            value={depositId}
            onChange={(e) => setDepositId(e.target.value)}
            className="w-full px-3 py-2 rounded-lg bg-white/10 text-white border border-cyan-400/30"
          />
          <input
            type="text"
            placeholder="Recipient"
            value={recipient}
            onChange={(e) => setRecipient(e.target.value)}
            className="w-full px-3 py-2 rounded-lg bg-white/10 text-white border border-cyan-400/30"
          />
          <div className="flex gap-4 items-center">
            <label className="text-white/80">Output asset from bridge:</label>
            <select
              value={outputAsset}
              onChange={(e) => setOutputAsset(Number(e.target.value) as 0 | 1)}
              className="px-3 py-2 rounded-lg bg-white/10 text-white border border-cyan-400/30"
            >
              <option value={OUTPUT_ASSET_ETH}>ETH</option>
              <option value={OUTPUT_ASSET_WETH}>WETH</option>
            </select>
          </div>
          <div className="flex gap-4 items-center">
            <label className="text-white/80">Stablecoin:</label>
            <select
              value={stablecoin}
              onChange={(e) => setStablecoin(e.target.value as typeof stablecoin)}
              className="px-3 py-2 rounded-lg bg-white/10 text-white border border-cyan-400/30"
            >
              {STABLECOIN_OPTIONS.map((o) => (
                <option key={o.value} value={o.value}>{o.label}</option>
              ))}
            </select>
          </div>
          <input
            type="text"
            placeholder="Amount out min (wei or units)"
            value={amountOutMin}
            onChange={(e) => setAmountOutMin(e.target.value)}
            className="w-full px-3 py-2 rounded-lg bg-white/10 text-white border border-cyan-400/30"
          />
          <div className="flex gap-4 items-center">
            <label className="text-white/80">Router:</label>
            <label className="flex items-center gap-2 cursor-pointer">
              <input
                type="radio"
                checked={!useEnhancedRouter}
                onChange={() => setUseEnhancedRouter(false)}
                className="rounded"
              />
              <span>Basic (SwapRouter)</span>
            </label>
            <label className="flex items-center gap-2 cursor-pointer">
              <input
                type="radio"
                checked={useEnhancedRouter}
                onChange={() => setUseEnhancedRouter(true)}
                className="rounded"
              />
              <span>Enhanced (EnhancedSwapRouter)</span>
            </label>
          </div>
          <button
            type="button"
            disabled={isPending || isConfirming || !depositId || !recipient || !amountOutMin || !onMainnet}
            onClick={handleBridgeAndSwap}
            className="px-4 py-2 rounded-lg bg-cyan-500 text-white font-medium disabled:opacity-50"
          >
            {isPending || isConfirming ? 'Confirming...' : 'Bridge & Swap'}
          </button>
        </div>
      </section>
    </div>
  );
}
