import { useState, useEffect } from 'react';
import { getBalance, getUtxos, getTransaction, getRecentTransactions, formatToshis } from '../lib/api';
import type { Balance, UTXO, Transaction, RecentTransaction } from '../lib/api';
import { Stack, Divider } from './ui/Layout';
import {
  Terminal,
  Section,
  LabelValue,
  DataTable,
  DataRow,
  ActionBar,
  Message,
} from './ui/Terminal';

type SearchResult =
  | { type: 'account'; did: string; handle?: string; balance: Balance; utxos: UTXO[] }
  | { type: 'transaction'; txId: string; transaction: Transaction }
  | null;

const handleCache = new Map<string, string>();

async function resolveHandle(input: string): Promise<{ did: string; handle?: string } | null> {
  // If it's already a DID, return it
  if (input.startsWith('did:')) {
    // Try to get handle for display
    try {
      const res = await fetch(`https://plc.directory/${input}`);
      if (res.ok) {
        const doc = await res.json();
        const handle = doc.alsoKnownAs?.[0]?.replace('at://', '');
        if (handle) handleCache.set(input, handle);
        return { did: input, handle };
      }
    } catch {}
    return { did: input };
  }

  // Remove @ prefix if present
  const handle = input.startsWith('@') ? input.slice(1) : input;

  // Check cache
  if (handleCache.has(handle)) {
    return { did: handleCache.get(handle)!, handle };
  }

  // Resolve handle to DID
  try {
    const res = await fetch(`https://bsky.social/xrpc/com.atproto.identity.resolveHandle?handle=${encodeURIComponent(handle)}`);
    if (res.ok) {
      const data = await res.json();
      handleCache.set(handle, data.did);
      return { did: data.did, handle };
    }
  } catch {}

  return null;
}

async function resolveDid(did: string): Promise<string> {
  if (handleCache.has(did)) return handleCache.get(did)!;

  try {
    // For did:web, extract the domain directly
    if (did.startsWith('did:web:')) {
      const domain = did.replace('did:web:', '');
      handleCache.set(did, domain);
      return domain;
    }

    // For did:plc, use PLC directory
    if (did.startsWith('did:plc:')) {
      const res = await fetch(`https://plc.directory/${did}`);
      if (res.ok) {
        const doc = await res.json();
        const handle = doc.alsoKnownAs?.[0]?.replace('at://', '') || did;
        handleCache.set(did, handle);
        return handle;
      }
    }
  } catch {}

  return did;
}

export default function Explorer() {
  const [query, setQuery] = useState('');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [result, setResult] = useState<SearchResult>(null);
  const [resolvedHandles, setResolvedHandles] = useState<Map<string, string>>(new Map());
  const [recentTxs, setRecentTxs] = useState<RecentTransaction[]>([]);
  const [loadingRecent, setLoadingRecent] = useState(true);

  // Load recent transactions on mount
  useEffect(() => {
    const loadRecent = async () => {
      try {
        const data = await getRecentTransactions(20);
        setRecentTxs(data.transactions);
      } catch (e) {
        console.error('Failed to load recent transactions:', e);
      } finally {
        setLoadingRecent(false);
      }
    };
    loadRecent();
  }, []);

  const search = async () => {
    if (!query.trim()) return;

    setLoading(true);
    setError(null);
    setResult(null);

    const input = query.trim();

    try {
      // Check if it looks like a transaction ID (TID format: 13 chars, alphanumeric)
      const isTxId = /^[a-z0-9]{13}$/i.test(input);

      if (isTxId) {
        // Search for transaction
        const txResult = await getTransaction(input);

        // Resolve handles for display
        const dids = new Set<string>();
        txResult.transaction.outputs.forEach(o => dids.add(o.owner));
        const trigger = txResult.transaction.trigger;
        if (trigger) {
          if ('followerDid' in trigger) {
            dids.add(trigger.followerDid);
          } else if ('senderDid' in trigger) {
            dids.add(trigger.senderDid);
          }
        }

        const handles = new Map<string, string>();
        await Promise.all(
          Array.from(dids).map(async did => {
            const handle = await resolveDid(did);
            handles.set(did, handle);
          })
        );
        setResolvedHandles(handles);

        setResult({
          type: 'transaction',
          txId: input,
          transaction: txResult.transaction,
        });
      } else {
        // Search for account
        const resolved = await resolveHandle(input);
        if (!resolved) {
          throw new Error('Could not resolve handle or DID');
        }

        const [balanceResult, utxosResult] = await Promise.all([
          getBalance(resolved.did),
          getUtxos(resolved.did),
        ]);

        setResult({
          type: 'account',
          did: resolved.did,
          handle: resolved.handle,
          balance: balanceResult,
          utxos: utxosResult.utxos,
        });
      }
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Search failed');
    } finally {
      setLoading(false);
    }
  };

  const formatDid = (did: string) => {
    const handle = resolvedHandles.get(did);
    if (handle && handle !== did) {
      return `@${handle}`;
    }
    return did.length > 24 ? `${did.slice(0, 24)}...` : did;
  };

  const handleKeyDown = (e: React.KeyboardEvent) => {
    if (e.key === 'Enter') {
      search();
    }
  };

  return (
    <Terminal subtitle="EXPLORER" showBack>
      <Section title="SEARCH">
        <Stack gap="sm">
          <div className="input-field" onKeyDown={handleKeyDown}>
            <label className="input-label">QUERY:</label>{' '}
            <input
              type="text"
              value={query}
              onChange={(e) => setQuery(e.target.value)}
              placeholder="@handle, did:plc:..., or txid"
              style={{ width: '300px' }}
            />
          </div>
          <button className="btn" onClick={search} disabled={loading || !query.trim()}>
            {loading ? '[SEARCHING...]' : '[SEARCH]'}
          </button>
        </Stack>
      </Section>

      {error && (
        <>
          <Divider />
          <Section>
            <Message type="error">{error}</Message>
          </Section>
        </>
      )}

      {/* Show recent transactions when no search result */}
      {!result && !error && (
        <>
          <Divider />
          <Section title="RECENT TRANSACTIONS">
            {loadingRecent ? (
              <p className="text-muted">Loading...</p>
            ) : recentTxs.length === 0 ? (
              <p className="text-muted">No transactions yet</p>
            ) : (
              <DataTable
                headers={['TYPE', 'AMOUNT', 'TIME', 'TX']}
                widths={['5rem', '10rem', '8rem', '1fr']}
              >
                {recentTxs.map((tx) => (
                  <DataRow
                    key={tx.txId}
                    cells={[
                      tx.type.toUpperCase(),
                      `${formatToshis(tx.totalAmount)} @toshis`,
                      new Date(tx.createdAt).toLocaleTimeString(),
                      <a href={`/tx/${tx.txId}`} className="link">{tx.txId}</a>,
                    ]}
                    widths={['5rem', '10rem', '8rem', '1fr']}
                  />
                ))}
              </DataTable>
            )}
          </Section>
        </>
      )}

      {result?.type === 'account' && (
        <>
          <Divider />
          <Section title="ACCOUNT">
            <Stack gap="xs">
              {result.handle && (
                <LabelValue label="HANDLE" value={`@${result.handle}`} />
              )}
              <LabelValue label="DID" value={result.did.length > 40 ? `${result.did.slice(0, 40)}...` : result.did} />
              <LabelValue label="BALANCE" value={`${formatToshis(result.balance.balance)} @toshis`} />
              <LabelValue label="UTXOS" value={result.balance.utxoCount} />
            </Stack>
          </Section>

          {result.utxos.length > 0 && (
            <>
              <Divider />
              <Section title="UNSPENT OUTPUTS">
                <DataTable
                  headers={['#', 'AMOUNT', 'TX']}
                  widths={['2rem', '10rem', '1fr']}
                >
                  {result.utxos.slice(0, 10).map((utxo, i) => (
                    <DataRow
                      key={`${utxo.txId}:${utxo.index}`}
                      cells={[
                        String(i + 1),
                        `${formatToshis(utxo.amount)} @toshis`,
                        <a href={`/tx/${utxo.txId}`} className="link">{utxo.txId}</a>,
                      ]}
                      widths={['2rem', '10rem', '1fr']}
                    />
                  ))}
                </DataTable>
                {result.utxos.length > 10 && (
                  <p className="text-muted">...and {result.utxos.length - 10} more</p>
                )}
              </Section>
            </>
          )}
        </>
      )}

      {result?.type === 'transaction' && (
        <>
          <Divider />
          <Section title="TRANSACTION">
            <Stack gap="xs">
              <LabelValue label="TXID" value={result.txId} />
              <LabelValue label="TYPE" value={result.transaction.type.toUpperCase()} />
              <LabelValue label="DATE" value={new Date(result.transaction.createdAt).toLocaleString()} />
              {result.transaction.trigger && 'followerDid' in result.transaction.trigger && (
                <LabelValue label="TRIGGERED BY" value={formatDid((result.transaction.trigger as { followerDid: string }).followerDid)} />
              )}
              {result.transaction.trigger && 'senderDid' in result.transaction.trigger && (
                <LabelValue label="SENT BY" value={formatDid((result.transaction.trigger as { senderDid: string }).senderDid)} />
              )}
            </Stack>
          </Section>

          <Divider />
          <Section title="RECIPIENTS">
            <DataTable
              headers={['#', 'AMOUNT', 'TO']}
              widths={['2rem', '10rem', '1fr']}
            >
              {result.transaction.outputs.map((output, i) => (
                <DataRow
                  key={i}
                  cells={[
                    String(i + 1),
                    `${formatToshis(output.amount)} @toshis`,
                    formatDid(output.owner),
                  ]}
                  widths={['2rem', '10rem', '1fr']}
                />
              ))}
            </DataTable>
          </Section>

          {result.transaction.inputs.length > 0 && (
            <>
              <Divider />
              <Section title="SPENT COINS">
                <DataTable
                  headers={['#', 'SOURCE TX']}
                  widths={['2rem', '1fr']}
                >
                  {result.transaction.inputs.map((input, i) => (
                    <DataRow
                      key={i}
                      cells={[
                        String(i + 1),
                        <a href={`/tx/${input.txId}`} className="link">{input.txId}:{input.index}</a>,
                      ]}
                      widths={['2rem', '1fr']}
                    />
                  ))}
                </DataTable>
              </Section>
            </>
          )}
        </>
      )}

      <Divider />
      <ActionBar>
        <a href="/wallet" className="btn">[WALLET]</a>
        <a href="/whitepaper" className="btn secondary">[WHITEPAPER]</a>
      </ActionBar>
    </Terminal>
  );
}
