import type { FeeEstimates } from './shared';
import { useState } from 'react';
import { Link } from 'react-router';
import { Bitcoin, Coins, Loader2, Zap } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { walletSectionPath } from './shared';
import { formatSats } from './format';
import { Amount } from './Amount';
import { CopyField } from './CopyField';
import { EmptyWallet, UnsupportedSection } from './EmptyWallet';
import { UnlockPrompt } from './LockBadge';
import { useSelectedWallet } from './useSelectedWallet';
import { useCoinSelection } from './useCoinSelection';
import { useLockCountdown } from './useLockCountdown';
import { useBalances, useCapabilities, useFees, useUtxos, useWalletOperations } from './useWalletData';
import { PayInvoiceDialog } from './dialogs/PayInvoiceDialog';

// Sending — the only part of the app that genuinely needs an unlocked wallet.
//
// The form is fully usable while locked: you can compose the whole spend, see the fee, review the coins.
// Only the submit is blocked, with an inline unlock prompt above it rather than a modal wall across the
// screen. That ordering is deliberate — you should be able to read what you are about to sign before you
// are asked for the passphrase.
//
// The selected coins come from `?coins=` (useCoinSelection), so the Coins section and this one agree
// through the URL rather than a shared store.

const FEE_PRESETS: { key: keyof FeeEstimates; label: string; hint: string }[] = [
  { key: 'fastestFee', label: 'Fastest', hint: 'next block' },
  { key: 'halfHourFee', label: 'Fast', hint: '~30 min' },
  { key: 'hourFee', label: 'Normal', hint: '~1 hour' },
  { key: 'economyFee', label: 'Economy', hint: 'hours' },
  { key: 'minimumFee', label: 'Minimum', hint: 'whenever' },
];

export const SendView = () => {
  const { wallet, walletId, isLoading } = useSelectedWallet();
  const { capabilities } = useCapabilities(walletId);
  const canOnchain = capabilities.includes('onchainSend');
  const canLightning = capabilities.includes('lightningSend');

  if (!walletId) return <EmptyWallet isLoading={isLoading} />;
  if (!canOnchain && !canLightning) return <UnsupportedSection what="sending" />;

  return (
    <div className="h-full overflow-y-auto p-4">
      <Tabs defaultValue={canOnchain ? 'onchain' : 'lightning'} className="max-w-2xl">
        {canOnchain && canLightning && (
          <TabsList className="mb-4 w-fit">
            <TabsTrigger value="onchain">
              <Bitcoin className="mr-1.5 h-3.5 w-3.5" />
              On-chain
            </TabsTrigger>
            <TabsTrigger value="lightning">
              <Zap className="mr-1.5 h-3.5 w-3.5" />
              Lightning
            </TabsTrigger>
          </TabsList>
        )}

        {canOnchain && (
          <TabsContent value="onchain" className="mt-0">
            <OnchainSendForm walletId={walletId} walletName={wallet?.name ?? 'this wallet'} />
          </TabsContent>
        )}
        {canLightning && (
          <TabsContent value="lightning" className="mt-0">
            <LightningSendPanel walletId={walletId} walletName={wallet?.name ?? 'this wallet'} />
          </TabsContent>
        )}
      </Tabs>
    </div>
  );
};

type FormProps = { walletId: number; walletName: string };

const OnchainSendForm = ({ walletId, walletName }: FormProps) => {
  const { balances } = useBalances(walletId);
  const { fees } = useFees(walletId);
  const { capabilities } = useCapabilities(walletId);
  const { selected, clear } = useCoinSelection();
  const { utxos } = useUtxos(walletId, capabilities.includes('coinControl'));
  const { send } = useWalletOperations(walletId);
  const { hasSeed, unlocked } = useLockCountdown(walletId);

  const [address, setAddress] = useState('');
  const [amount, setAmount] = useState('');
  const [sendAll, setSendAll] = useState(false);
  const [satPerVbyte, setSatPerVbyte] = useState('');
  const [label, setLabel] = useState('');
  const [broadcast, setBroadcast] = useState<{ txid: string; feeSats: number } | null>(null);

  // A seeded wallet must be unlocked to sign. A wallet with no seed of its own (a remote node) signs
  // upstream, so there is nothing to unlock and the form is always live.
  const needsUnlock = hasSeed === true && !unlocked;
  const selectedUtxos = utxos.filter((u) => selected.includes(`${u.txid}:${u.vout}`));
  const selectedTotal = selectedUtxos.reduce((sum, u) => sum + u.amountSats, 0);

  const feeRate = Number(satPerVbyte);
  const amountSats = Number(amount);
  const canSubmit =
    !!address.trim() &&
    (sendAll || (Number.isFinite(amountSats) && amountSats > 0)) &&
    Number.isFinite(feeRate) &&
    feeRate >= 1 &&
    !needsUnlock &&
    !send.isPending;

  const submit = async (ev: React.FormEvent) => {
    ev.preventDefault();
    if (!canSubmit) return;
    const result = await send.mutateAsync({
      address: address.trim(),
      amountSats: sendAll ? undefined : amountSats,
      sendAll: sendAll || undefined,
      satPerVbyte: feeRate,
      outpoints: selected.length > 0 ? selected : undefined,
      label: label.trim() || undefined,
    });
    setBroadcast({ txid: result.txid, feeSats: result.feeSats });
    setAddress('');
    setAmount('');
    setLabel('');
    setSendAll(false);
    clear();
  };

  if (broadcast) {
    return (
      <section className="rounded-xl border border-emerald-500/40 bg-emerald-500/5 p-4">
        <h3 className="text-sm font-semibold">Broadcast</h3>
        <p className="mt-1 text-xs text-muted-foreground">
          Paid a fee of {formatSats(broadcast.feeSats)} sats. It will confirm when a miner includes it.
        </p>
        <CopyField className="mt-3" value={broadcast.txid} label="txid" wrap />
        <Button size="sm" variant="outline" className="mt-3" onClick={() => setBroadcast(null)}>
          Send another
        </Button>
      </section>
    );
  }

  return (
    <form onSubmit={submit} className="space-y-4">
      <div className="rounded-xl border border-border p-4">
        <div className="flex items-baseline justify-between">
          <h3 className="text-[11px] font-semibold uppercase tracking-wide text-muted-foreground">Spendable</h3>
          {/* Frozen coins are confirmed and are the wallet's, but coin selection will not touch them. This
              header said "Spendable" over a figure that included them, so a max-value send was rejected as
              having no spendable UTXOs while the number above it said otherwise. */}
          <Amount
            sats={balances ? balances.onchainConfirmed - balances.onchainFrozen : null}
            className="text-sm font-semibold"
          />
        </div>
        {!!balances?.onchainFrozen && (
          <p className="mt-1 text-right text-[11px] text-muted-foreground">
            {formatSats(balances.onchainFrozen)} sats frozen and excluded
          </p>
        )}
      </div>

      <div className="space-y-1.5">
        <Label htmlFor="wallet-send-address">To address</Label>
        <Input
          id="wallet-send-address"
          value={address}
          spellCheck={false}
          placeholder="bc1q…"
          onChange={(ev) => setAddress(ev.target.value)}
          className="font-mono text-xs"
        />
      </div>

      <div className="space-y-1.5">
        <Label htmlFor="wallet-send-amount">Amount (sats)</Label>
        <div className="flex items-center gap-2">
          <Input
            id="wallet-send-amount"
            type="number"
            min={0}
            value={sendAll ? '' : amount}
            disabled={sendAll}
            placeholder={sendAll ? 'everything' : '0'}
            onChange={(ev) => setAmount(ev.target.value)}
            className="w-48"
          />
          <button
            type="button"
            onClick={() => setSendAll((v) => !v)}
            className={`rounded-md px-2.5 py-1 text-xs transition-colors ${
              sendAll ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground hover:bg-muted/70'
            }`}
          >
            Send max
          </button>
        </div>
      </div>

      <div className="space-y-1.5">
        <Label htmlFor="wallet-send-fee">Fee rate (sat/vB)</Label>
        <div className="flex flex-wrap gap-1.5">
          {fees &&
            FEE_PRESETS.map(({ key, label: presetLabel, hint }) => (
              <button
                key={key}
                type="button"
                onClick={() => setSatPerVbyte(String(fees[key]))}
                className={`rounded-md px-2.5 py-1 text-xs transition-colors ${
                  satPerVbyte === String(fees[key])
                    ? 'bg-primary text-primary-foreground'
                    : 'bg-muted text-muted-foreground hover:bg-muted/70'
                }`}
                title={hint}
              >
                {presetLabel} · {fees[key]}
              </button>
            ))}
        </div>
        <Input
          id="wallet-send-fee"
          type="number"
          min={1}
          value={satPerVbyte}
          placeholder="1"
          onChange={(ev) => setSatPerVbyte(ev.target.value)}
          className="w-32"
        />
      </div>

      {capabilities.includes('coinControl') && (
        <div className="rounded-xl border border-border p-3">
          <div className="flex items-center gap-2 text-xs">
            <Coins className="h-3.5 w-3.5 text-muted-foreground" />
            {selected.length === 0 ? (
              <span className="flex-1 text-muted-foreground">
                Automatic coin selection.{' '}
                <Link to={walletSectionPath('coins', walletId)} className="text-primary hover:underline">
                  Pick coins
                </Link>
              </span>
            ) : (
              <>
                <span className="flex-1">
                  {selected.length} coin{selected.length === 1 ? '' : 's'} selected · <Amount sats={selectedTotal} />
                </span>
                <button type="button" onClick={clear} className="text-primary hover:underline">
                  clear
                </button>
              </>
            )}
          </div>
        </div>
      )}

      <div className="space-y-1.5">
        <Label htmlFor="wallet-send-label">Label (optional)</Label>
        <Input
          id="wallet-send-label"
          value={label}
          placeholder="what this payment is for"
          onChange={(ev) => setLabel(ev.target.value)}
        />
      </div>

      {needsUnlock && <UnlockPrompt walletId={walletId} walletName={walletName} />}

      <Button type="submit" disabled={!canSubmit}>
        {send.isPending && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
        Sign and broadcast
      </Button>
    </form>
  );
};

const LightningSendPanel = ({ walletId, walletName }: FormProps) => {
  const { balances } = useBalances(walletId);
  const { hasSeed, unlocked } = useLockCountdown(walletId);
  const [payOpen, setPayOpen] = useState(false);
  const needsUnlock = hasSeed === true && !unlocked;

  return (
    <div className="space-y-4">
      <div className="rounded-xl border border-border p-4">
        <div className="flex items-baseline justify-between">
          <h3 className="text-[11px] font-semibold uppercase tracking-wide text-muted-foreground">Lightning balance</h3>
          <Amount sats={balances?.lightningBalance ?? null} className="text-sm font-semibold" />
        </div>
      </div>

      {needsUnlock && <UnlockPrompt walletId={walletId} walletName={walletName} />}

      <Button onClick={() => setPayOpen(true)} disabled={needsUnlock}>
        <Zap className="mr-2 h-4 w-4" />
        Pay an invoice
      </Button>

      {payOpen && <PayInvoiceDialog open={payOpen} onOpenChange={setPayOpen} walletId={walletId} />}
    </div>
  );
};
