/**
 * Transaction Screen - Reviews and broadcasts transactions.
 * 
 * Provides:
 * - Transaction details review
 * - Input/output inspection
 * - Fee calculation display
 * - Broadcast confirmation
 */

import React, { useState, useEffect, useCallback } from 'react';
import { Box, Text, useInput } from 'ink';
import { ConfirmDialog } from '../components/Dialog.js';
import { useNavigation } from '../hooks/useNavigation.js';
import { useAppContext, useStatus } from '../hooks/useAppContext.js';
import { colors, logoSmall, formatSatoshis, formatHex } from '../theme.js';
import { copyToClipboard } from '../utils/clipboard.js';
import type { XOInvitation } from '@xo-cash/types';

/**
 * Action menu items.
 */
const actionItems = [
  { label: 'Broadcast Transaction', value: 'broadcast' },
  { label: 'Sign Transaction', value: 'sign' },
  { label: 'Copy Transaction Hex', value: 'copy' },
  { label: 'Back to Invitation', value: 'back' },
];

/**
 * Transaction Screen Component.
 */
export function TransactionScreen(): React.ReactElement {
  const { navigate, goBack, data: navData } = useNavigation();
  const { invitationController, showError, showInfo, confirm } = useAppContext();
  const { setStatus } = useStatus();

  // Extract invitation ID from navigation data
  const invitationId = navData.invitationId as string | undefined;

  // State
  const [invitation, setInvitation] = useState<XOInvitation | null>(null);
  const [focusedPanel, setFocusedPanel] = useState<'inputs' | 'outputs' | 'actions'>('actions');
  const [selectedActionIndex, setSelectedActionIndex] = useState(0);
  const [isLoading, setIsLoading] = useState(false);
  const [showBroadcastConfirm, setShowBroadcastConfirm] = useState(false);

  /**
   * Load invitation data.
   */
  const loadInvitation = useCallback(() => {
    if (!invitationId) {
      showError('No invitation ID provided');
      goBack();
      return;
    }

    const tracked = invitationController.getInvitation(invitationId);
    if (!tracked) {
      showError('Invitation not found');
      goBack();
      return;
    }

    setInvitation(tracked.invitation);
  }, [invitationId, invitationController, showError, goBack]);

  // Load on mount
  useEffect(() => {
    loadInvitation();
  }, [loadInvitation]);

  /**
   * Broadcast transaction.
   */
  const broadcastTransaction = useCallback(async () => {
    if (!invitationId) return;

    setShowBroadcastConfirm(false);
    setIsLoading(true);
    setStatus('Broadcasting transaction...');

    try {
      const txHash = await invitationController.broadcastTransaction(invitationId);
      showInfo(
        `Transaction Broadcast Successful!\n\n` +
        `Transaction Hash:\n${txHash}\n\n` +
        `The transaction has been submitted to the network.`
      );
      navigate('wallet');
    } catch (error) {
      showError(`Failed to broadcast: ${error instanceof Error ? error.message : String(error)}`);
    } finally {
      setIsLoading(false);
      setStatus('Ready');
    }
  }, [invitationId, invitationController, showInfo, showError, navigate, setStatus]);

  /**
   * Sign transaction.
   */
  const signTransaction = useCallback(async () => {
    if (!invitationId) return;

    setIsLoading(true);
    setStatus('Signing transaction...');

    try {
      await invitationController.signInvitation(invitationId);
      loadInvitation();
      showInfo('Transaction signed successfully!');
    } catch (error) {
      showError(`Failed to sign: ${error instanceof Error ? error.message : String(error)}`);
    } finally {
      setIsLoading(false);
      setStatus('Ready');
    }
  }, [invitationId, invitationController, loadInvitation, showInfo, showError, setStatus]);

  /**
   * Copy transaction hex.
   */
  const copyTransactionHex = useCallback(async () => {
    if (!invitation) return;

    try {
      await copyToClipboard(invitation.invitationIdentifier);
      showInfo(
        `Copied Invitation ID!\n\n` +
        `ID: ${invitation.invitationIdentifier}\n` +
        `Commits: ${invitation.commits.length}`
      );
    } catch (error) {
      showError(`Failed to copy: ${error instanceof Error ? error.message : String(error)}`);
    }
  }, [invitation, showInfo, showError]);

  /**
   * Handle action selection.
   */
  const handleAction = useCallback((action: string) => {
    switch (action) {
      case 'broadcast':
        setShowBroadcastConfirm(true);
        break;
      case 'sign':
        signTransaction();
        break;
      case 'copy':
        copyTransactionHex();
        break;
      case 'back':
        goBack();
        break;
    }
  }, [signTransaction, copyTransactionHex, goBack]);

  // Handle keyboard navigation
  useInput((input, key) => {
    if (showBroadcastConfirm) return;

    // Tab to switch panels
    if (key.tab) {
      setFocusedPanel(prev => {
        if (prev === 'inputs') return 'outputs';
        if (prev === 'outputs') return 'actions';
        return 'inputs';
      });
      return;
    }

    // Up/Down in actions
    if (focusedPanel === 'actions') {
      if (key.upArrow || input === 'k') {
        setSelectedActionIndex(prev => Math.max(0, prev - 1));
      } else if (key.downArrow || input === 'j') {
        setSelectedActionIndex(prev => Math.min(actionItems.length - 1, prev + 1));
      }
    }

    // Enter to select
    if (key.return && focusedPanel === 'actions') {
      const action = actionItems[selectedActionIndex];
      if (action) {
        handleAction(action.value);
      }
    }
  }, { isActive: !showBroadcastConfirm });

  // Extract transaction data from invitation
  const commits = invitation?.commits ?? [];
  const inputs: Array<{ txid: string; index: number; value?: bigint; inputIdentifier?: string }> = [];
  const outputs: Array<{ value?: bigint; lockingBytecode: string; outputIdentifier?: string; isTemplate: boolean }> = [];
  const variables: Array<{ id: string; value: string }> = [];

  // Parse commits for inputs, outputs, and variables
  for (const commit of commits) {
    // Extract variables (to help understand output values)
    if (commit.data?.variables) {
      for (const variable of commit.data.variables) {
        variables.push({
          id: variable.variableIdentifier,
          value: String(variable.value),
        });
      }
    }

    if (commit.data?.inputs) {
      for (const input of commit.data.inputs) {
        // Convert Uint8Array to hex string if needed
        const txidHex = input.outpointTransactionHash 
          ? typeof input.outpointTransactionHash === 'string'
            ? input.outpointTransactionHash
            : Buffer.from(input.outpointTransactionHash).toString('hex')
          : undefined;
        
        // Skip inputs that are just placeholders (no txid)
        if (txidHex) {
          inputs.push({
            txid: txidHex,
            index: input.outpointIndex ?? 0,
            value: undefined, // Will be looked up from UTXO data
            inputIdentifier: (input as any).inputIdentifier,
          });
        }
      }
    }
    if (commit.data?.outputs) {
      for (const output of commit.data.outputs) {
        // Convert Uint8Array to hex string if needed
        const lockingBytecodeHex = output.lockingBytecode
          ? typeof output.lockingBytecode === 'string'
            ? output.lockingBytecode
            : Buffer.from(output.lockingBytecode).toString('hex')
          : undefined;
        
        // Check if this is a template-defined output (has outputIdentifier but no direct value)
        const isTemplateOutput = !!(output as any).outputIdentifier && !output.valueSatoshis;
        
        outputs.push({
          value: output.valueSatoshis,
          lockingBytecode: lockingBytecodeHex ?? '(pending)',
          outputIdentifier: (output as any).outputIdentifier,
          isTemplate: isTemplateOutput,
        });
      }
    }
  }

  // Try to resolve template output values from variables
  const resolvedOutputs = outputs.map(output => {
    if (output.isTemplate && output.outputIdentifier) {
      // Look for a matching variable (e.g., requestSatoshisOutput -> requestedSatoshis)
      const satoshiVar = variables.find(v => 
        v.id.toLowerCase().includes('satoshi') || 
        v.id.toLowerCase().includes('amount')
      );
      if (satoshiVar) {
        return {
          ...output,
          value: BigInt(satoshiVar.value),
          resolvedFrom: satoshiVar.id,
        };
      }
    }
    return output;
  });

  // Calculate totals (only for resolved values)
  const totalOut = resolvedOutputs.reduce((sum, o) => sum + (o.value ?? 0n), 0n);
  // Note: We can't calculate totalIn without UTXO lookup, so fee is unknown
  const hasUnresolvedOutputs = resolvedOutputs.some(o => o.value === undefined);
  const hasUnresolvedInputs = inputs.length > 0; // Input values are always unknown from commit data

  return (
    <Box flexDirection="column" flexGrow={1}>
      {/* Header */}
      <Box borderStyle="single" borderColor={colors.secondary} paddingX={1}>
        <Text color={colors.primary} bold>{logoSmall} - Transaction Review</Text>
      </Box>

      {/* Summary box */}
      <Box
        borderStyle="single"
        borderColor={colors.primary}
        marginTop={1}
        marginX={1}
        paddingX={1}
        flexDirection="column"
      >
        <Text color={colors.primary} bold> Transaction Summary </Text>
        {invitation ? (
          <Box flexDirection="column" marginTop={1}>
            <Text color={colors.text}>Inputs: {inputs.length} | Outputs: {resolvedOutputs.length} | Commits: {commits.length}</Text>
            {hasUnresolvedInputs && (
              <Text color={colors.textMuted}>Total In: (requires UTXO lookup)</Text>
            )}
            <Text color={colors.warning}>Total Out: {formatSatoshis(totalOut)}{hasUnresolvedOutputs ? ' (partial)' : ''}</Text>
            {hasUnresolvedInputs ? (
              <Text color={colors.textMuted}>Fee: (calculated at broadcast)</Text>
            ) : (
              <Text color={colors.info}>Fee: {formatSatoshis(0n)}</Text>
            )}
          </Box>
        ) : (
          <Text color={colors.textMuted}>Loading...</Text>
        )}
      </Box>

      {/* Inputs and Outputs */}
      <Box flexDirection="row" marginTop={1} marginX={1} flexGrow={1}>
        {/* Inputs */}
        <Box
          borderStyle="single"
          borderColor={focusedPanel === 'inputs' ? colors.focus : colors.border}
          width="50%"
          flexDirection="column"
          paddingX={1}
        >
          <Text color={colors.primary} bold> Inputs </Text>
          <Box flexDirection="column" marginTop={1}>
            {inputs.length === 0 ? (
              <Text color={colors.textMuted}>No inputs</Text>
            ) : (
              inputs.map((input, index) => (
                <Box key={`${input.txid}-${input.index}`} flexDirection="column" marginBottom={1}>
                  <Text color={colors.text}>
                    {index + 1}. {formatHex(input.txid, 12)}:{input.index}
                  </Text>
                  {input.value !== undefined && (
                    <Text color={colors.textMuted}>   {formatSatoshis(input.value)}</Text>
                  )}
                </Box>
              ))
            )}
          </Box>
        </Box>

        {/* Outputs */}
        <Box
          borderStyle="single"
          borderColor={focusedPanel === 'outputs' ? colors.focus : colors.border}
          width="50%"
          flexDirection="column"
          paddingX={1}
          marginLeft={1}
        >
          <Text color={colors.primary} bold> Outputs </Text>
          <Box flexDirection="column" marginTop={1}>
            {resolvedOutputs.length === 0 ? (
              <Text color={colors.textMuted}>No outputs</Text>
            ) : (
              resolvedOutputs.map((output, index) => (
                <Box key={index} flexDirection="column" marginBottom={1}>
                  <Text color={colors.text}>
                    {index + 1}. {output.value !== undefined ? formatSatoshis(output.value) : '(pending)'}
                    {output.outputIdentifier && (
                      <Text color={colors.info}> [{output.outputIdentifier}]</Text>
                    )}
                  </Text>
                  <Text color={colors.textMuted}>   {output.lockingBytecode !== '(pending)' ? formatHex(output.lockingBytecode, 20) : '(pending)'}</Text>
                  {(output as any).resolvedFrom && (
                    <Text color={colors.textMuted} dimColor>   (from ${(output as any).resolvedFrom})</Text>
                  )}
                </Box>
              ))
            )}
          </Box>
        </Box>
      </Box>

      {/* Actions */}
      <Box
        borderStyle="single"
        borderColor={focusedPanel === 'actions' ? colors.focus : colors.border}
        marginTop={1}
        marginX={1}
        paddingX={1}
        flexDirection="column"
      >
        <Text color={colors.primary} bold> Actions </Text>
        <Box flexDirection="column" marginTop={1}>
          {actionItems.map((item, index) => (
            <Text
              key={item.value}
              color={index === selectedActionIndex && focusedPanel === 'actions' ? colors.focus : colors.text}
              bold={index === selectedActionIndex && focusedPanel === 'actions'}
            >
              {index === selectedActionIndex && focusedPanel === 'actions' ? '▸ ' : '  '}
              {item.label}
            </Text>
          ))}
        </Box>
      </Box>

      {/* Help text */}
      <Box marginTop={1} marginX={1}>
        <Text color={colors.textMuted} dimColor>
          Tab: Switch focus • Enter: Select • Esc: Back
        </Text>
      </Box>

      {/* Broadcast confirmation dialog */}
      {showBroadcastConfirm && (
        <Box
          position="absolute"
          flexDirection="column"
          alignItems="center"
          justifyContent="center"
          width="100%"
          height="100%"
        >
          <ConfirmDialog
            title="Broadcast Transaction"
            message="Are you sure you want to broadcast this transaction? This action cannot be undone."
            onConfirm={broadcastTransaction}
            onCancel={() => setShowBroadcastConfirm(false)}
            isActive={showBroadcastConfirm}
          />
        </Box>
      )}
    </Box>
  );
}
