// Unified API — Tauri IPC in native builds, HTTP fallback in browser
import { invoke } from '@tauri-apps/api/core';

// API key for backend authentication — embedded in frontend since both run on same machine
const API_KEY = import.meta.env.VITE_API_KEY || '';

// Dynamic API URL: uses same host as the page (works for LAN/Tailscale access)
// When running in Tauri, IPC is used instead of HTTP — this URL is ignored.
function getApiUrl(): string {
  if (typeof window === 'undefined') return 'http://127.0.0.1:14195/api';
  const host = window.location.hostname;
  const protocol = window.location.protocol;
  return `${protocol}//${host}:14195/api`;
}

// Common request headers
function getHeaders(): Record<string, string> {
  const headers: Record<string, string> = { 'Content-Type': 'application/json' };
  if (API_KEY) headers['X-API-Key'] = API_KEY;
  return headers;
}

// Detect Tauri: window.__TAURI__ exists when running in Tauri WebView
function isTauri(): boolean {
  return typeof window !== 'undefined' && '__TAURI__' in window;
}

// ================= Core helpers =================

async function proxy(command: string, args: Record<string, unknown>): Promise<any> {
  if (isTauri()) {
    return invoke('python_proxy', { command, args });
  }
  const resp = await fetch(`${getApiUrl()}/${command}`, {
    method: 'POST',
    headers: getHeaders(),
    body: JSON.stringify(args),
  });
  if (!resp.ok) {
    const err = await resp.json().catch(() => ({ error: resp.statusText }));
    throw new Error(err.error || `API error ${resp.status}`);
  }
  return resp.json();
}

async function rpc(method: string, params: unknown[] = []): Promise<any> {
  if (isTauri()) {
    return invoke('rpc_command', { method, params });
  }
  const resp = await fetch(`${getApiUrl()}/${method}`, {
    method: 'POST',
    headers: getHeaders(),
    body: JSON.stringify({ params }),
  });
  return resp.json();
}

// ================= Wallet operations (via Python proxy) =================

export async function generateSeed(strength: number = 128): Promise<string> {
  const data = await proxy('generate_seed', { strength });
  return data.seed;
}

export interface WalletInfo {
  name: string;
  fingerprint: string;
  encrypted: boolean;
  created: string;
  xpub: string;
  derivation_path: string;
  seed: string;
}

export interface AddressInfo {
  address: string;
  path: string;
  pubkey: string;
  privkey_wif: string;
  index: number;
  internal: boolean;
  type: string;
}

export async function createWallet(
  seed: string,
  walletName: string,
  password: string = '',
): Promise<{ wallet: WalletInfo; addresses: AddressInfo[] }> {
  const data = await proxy('create_wallet', {
    seed,
    wallet_name: walletName,
    password,
  });
  return data;
}

export async function deriveAddresses(
  wallet: any,
  numAddresses: number = 5,
  derivationType: string = 'bech32',
  password: string = '',
): Promise<AddressInfo[]> {
  // H10: Send wallet object (xpub-based) instead of raw mnemonic
  const data = await proxy('derive_addresses', {
    wallet,
    num_addresses: numAddresses,
    derivation_type: derivationType,
    password,
  });
  return data.addresses;
}

// ================= Bitcoin RPC (native Rust) =================

export async function getBlockCount(): Promise<number> {
  const data = await proxy('get_block_count', {});
  return data.block_count;
}

export async function getNetworkInfo(): Promise<any> {
  const data = await proxy('get_network_info', {});
  return data;
}

export async function getBalance(
  addresses: string[],
): Promise<{ balance_btc: number; balance_sats: number }> {
  if (isTauri()) {
    return invoke('get_balance', { addresses });
  }
  const resp = await fetch(`${getApiUrl()}/get_balance`, {
    method: 'POST',
    headers: getHeaders(),
    body: JSON.stringify({ addresses }),
  });
  return resp.json();
}

export async function getUtxos(addresses: string[]): Promise<any[]> {
  if (isTauri()) {
    const data = await invoke('get_utxos', { addresses });
    return (data as any).utxos;
  }
  const resp = await fetch(`${getApiUrl()}/get_utxos`, {
    method: 'POST',
    headers: getHeaders(),
    body: JSON.stringify({ addresses }),
  });
  const data = await resp.json();
  return data.utxos;
}

// ================= Transaction history =================

export interface TxInfo {
  address: string;
  category: string;
  amount: number;
  confirmations: number;
  blockhash?: string;
  blockindex?: number;
  blocktime?: number;
  txid: string;
  walletconflicts?: string[];
  time?: number;
  timereceived?: number;
  comment?: string;
}

export async function getTxHistory(
  address: string,
  count: number = 20,
): Promise<TxInfo[]> {
  const data = await proxy('get_tx_history', { address, count });
  return data;
}

// ================= Fee estimation =================

export interface FeeEstimate {
  blocks: number;
  feerate_btc: number | null;
  feerate_sats_vb: number;
}

export async function estimateFee(blocks: number = 6): Promise<FeeEstimate> {
  const data = await proxy('estimate_fee', { blocks });
  return data;
}

// ================= Transaction builder =================

export interface TxOutput {
  address: string;
  amount: number;
}

export interface CoinSelectResult {
  selected: any[];
  total_input: number;
}

export interface PsbtResult {
  psbt: string;
  inputs: number;
  outputs: number;
  total_input: number;
  total_output: number;
  fee_btc: number;
  change_address: string | null;
  change_amount: number;
  selected_utxos?: any[];
  coin_selection: string;
  error?: string;
}

export async function createPsbt(
  wallet: any,
  outputs: TxOutput[],
  feeRate: number = 10.0,
  addresses: string[] | null = null,
  password: string = '',
  coinSelection: string = 'largest',
  selectedUtxos: any[] | null = null,
): Promise<PsbtResult> {
  return proxy('create_psbt', {
    wallet,
    outputs,
    fee_rate: feeRate,
    addresses,
    password,
    coin_selection: coinSelection,
    selected_utxos: selectedUtxos,
  });
}

export interface PsbtSigned {
  psbt: string;
  complete: boolean;
  all_signed: boolean;
  finalized: boolean;
  raw_tx_hex: string | null;
  error?: string;
}

export async function signPsbt(
  wallet: any,
  psbt: string,
  password: string = '',
): Promise<PsbtSigned> {
  return proxy('sign_psbt', { wallet, psbt: psbt, password });
}

export async function finalizePsbt(psbt: string): Promise<{ raw_tx_hex: string | null; complete: boolean }> {
  return proxy('finalize_psbt', { psbt });
}

export async function signAndFinalizePsbt(
  wallet: any,
  psbt: string,
  password: string = '',
): Promise<{ raw_tx_hex: string | null; complete: boolean; error?: string }> {
  return proxy('sign_and_finalize_psbt', { wallet, psbt, password });
}

export interface BroadcastResult {
  txid: string;
  broadcast: boolean;
  error?: string;
}

export async function broadcastTx(rawTxHex: string): Promise<BroadcastResult> {
  return proxy('broadcast', { raw_tx_hex: rawTxHex });
}

export async function decodePsbt(psbt: string): Promise<any> {
  return proxy('decode_psbt', { psbt });
}

// ================= Transaction status =================

export interface TxStatus {
  txid: string;
  confirmations: number;
  blockhash?: string;
  blocktime?: number;
  hex?: string;
  status: 'confirmed' | 'unconfirmed' | 'not_found';
}

export async function getTxStatus(txid: string): Promise<TxStatus> {
  if (isTauri()) {
    // Use rpc_command directly
    const result = await invoke('rpc_command', {
      method: 'getrawtransaction',
      params: [txid, true],
    });
    if (!result || result === null) {
      return { txid, confirmations: 0, status: 'not_found' };
    }
    const r = result as any;
    return {
      txid: r.txid,
      confirmations: r.confirmations || 0,
      blockhash: r.blockhash,
      blocktime: r.blocktime,
      hex: r.hex,
      status: r.confirmations >= 1 ? 'confirmed' : 'unconfirmed',
    };
  }
  const resp = await fetch(`${getApiUrl()}/rpc_call`, {
    method: 'POST',
    headers: getHeaders(),
    body: JSON.stringify({ method: 'getrawtransaction', params: [txid, true] }),
  });
  const result = await resp.json();
  if (!result.result) {
    return { txid, confirmations: 0, status: 'not_found' };
  }
  const r = result.result;
  return {
    txid: r.txid,
    confirmations: r.confirmations || 0,
    blockhash: r.blockhash,
    blocktime: r.blocktime,
    hex: r.hex,
    status: r.confirmations >= 1 ? 'confirmed' : 'unconfirmed',
  };
}

// ---- Persistence + Labels + UTXO Tree ----

// Unified API call helper for proxy-based commands
async function api({ method, params = {} }: { method: string; params?: Record<string, unknown> }): Promise<any> {
  if (isTauri()) {
    return invoke('python_proxy', { command: method, args: params });
  }
  const resp = await fetch(`${getApiUrl()}/${method}`, {
    method: 'POST',
    headers: getHeaders(),
    body: JSON.stringify(params),
  });
  return resp.json();
}

export interface WalletMeta {
  path: string;
  name: string;
  type: string;
  fingerprint: string;
  encrypted: boolean;
  modified: string;
  created: string;
}

export async function saveWallet(wallet: any, walletDir?: string): Promise<any> {
  return api({ method: 'save_wallet', params: { wallet, wallet_dir: walletDir } });
}

export async function loadWallet(fpath: string, password?: string): Promise<any> {
  return api({ method: 'load_wallet', params: { fpath, password } });
}

export async function listWallets(): Promise<{ wallets: WalletMeta[] }> {
  return api({ method: 'list_wallets' });
}

export async function setLabel(wallet: any, kind: string, identifier: string, label: string): Promise<any> {
  return api({ method: 'set_label', params: { wallet, kind, identifier, label } });
}

export async function getUtxoTree(utxos: any[], txHistory: any[]): Promise<any> {
  return api({ method: 'get_utxo_tree', params: { utxos, tx_history: txHistory } });
}

// ================= Multisig =================

export interface MultisigParticipant {
  name: string;
  local: boolean;
  mnemonic?: string;
  xpub?: string;
}

export interface MultisigWallet {
  type: 'multisig';
  name: string;
  m: number;
  n: number;
  threshold: number;
  participants: Array<{
    index: number;
    name: string;
    xpub: string;
    local: boolean;
  }>;
  local_indices: number[];
  descriptor: string;
  descriptor_hash: string;
  address: string;
  encrypted: boolean;
  created: string;
  file_path?: string;
}

export async function createMultisigWallet(
  m: number,
  n: number,
  participants: MultisigParticipant[],
  walletName: string,
  password: string = '',
): Promise<{ wallet: MultisigWallet; balance: any }> {
  return api({ method: 'create_multisig_wallet', params: {
    m, n, participants, wallet_name: walletName, password,
  }});
}

export async function getMultisigBalance(wallet: MultisigWallet): Promise<any> {
  return api({ method: 'get_multisig_balance', params: { wallet } });
}

export async function getMultisigUtxos(wallet: MultisigWallet): Promise<{ utxos: any[] }> {
  return api({ method: 'get_multisig_utxos', params: { wallet } });
}

export interface MultisigAddressInfo {
  index: number;
  address: string;
  chain: 'receive' | 'change';
}

export async function getMultisigAddresses(
  wallet: MultisigWallet,
  count: number = 5,
  change: number = 0,
): Promise<{ addresses: MultisigAddressInfo[] }> {
  return api({ method: 'get_multisig_addresses', params: { wallet, count, change } });
}

export interface MultisigPsbtResult {
  psbt: string;
  inputs: number;
  outputs: number;
  total_input: number;
  total_output: number;
  fee_btc: number;
  change_address: string | null;
  error?: string;
}

export async function createMultisigPsbt(
  wallet: MultisigWallet,
  outputs: TxOutput[],
  feeRate: number = 10.0,
  utxos: any[] | null = null,
): Promise<MultisigPsbtResult> {
  return api({ method: 'create_multisig_psbt', params: {
    wallet, outputs, fee_rate: feeRate, utxos,
  }});
}

export interface MultisigSignResult {
  psbt: string;
  signatures_added: number;
  error?: string;
}

export async function signMultisigPsbt(
  psbt: string,
  wallet: MultisigWallet,
  password: string = '',
): Promise<MultisigSignResult> {
  return api({ method: 'sign_multisig_psbt', params: { psbt, wallet, password } });
}

export async function combinePsbt(psbtHexList: string[]): Promise<{ psbt: string }> {
  return api({ method: 'combine_psbt', params: { psbt_hex_list: psbtHexList } });
}

export interface MultisigFinalizeResult {
  complete: boolean;
  raw_tx_hex: string | null;
  error?: string;
}

export async function finalizeMultisigPsbt(psbt: string): Promise<MultisigFinalizeResult> {
  return api({ method: 'finalize_multisig_psbt', params: { psbt } });
}