//! Tauri commands for the desktop wallet
//!
//! All commands are async and return Result<T, Error> which Tauri
//! serializes as { ok: T } or { error: string } to the frontend.

use serde::{Deserialize, Serialize};
use tauri::{AppHandle, Manager, State};

use crate::wallet::{WalletState, WalletAddress, NetworkConnection};
use crate::{Error, Result};

// ============================================================================
// Wallet Management Commands
// ============================================================================

/// Response from wallet creation
#[derive(Debug, Serialize)]
pub struct CreateWalletResponse {
    pub mnemonic: String,
    pub address: String,
}

/// Create a new wallet with a random mnemonic
#[tauri::command]
pub async fn create_wallet(
    app: AppHandle,
    state: State<'_, WalletState>,
    password: String,
) -> Result<CreateWalletResponse> {
    // Validate password strength
    if password.len() < 8 {
        return Err(Error::Crypto("Password must be at least 8 characters".to_string()));
    }

    // Set up data directory
    let app_data_dir = app.path().app_data_dir()
        .map_err(|e| Error::Internal(format!("Failed to get app data dir: {}", e)))?;
    state.set_data_dir(app_data_dir).await?;

    // Check if wallet already exists
    if state.wallet_exists().await {
        return Err(Error::Internal("Wallet already exists. Import or unlock instead.".to_string()));
    }

    // Create wallet with encryption (testnet by default for safety)
    let (mnemonic, address) = state.create(&password, true).await?;

    Ok(CreateWalletResponse { mnemonic, address })
}

/// Import request
#[derive(Debug, Deserialize)]
pub struct ImportWalletRequest {
    pub mnemonic: String,
    pub password: String,
}

/// Import a wallet from mnemonic phrase
#[tauri::command]
pub async fn import_wallet(
    app: AppHandle,
    state: State<'_, WalletState>,
    request: ImportWalletRequest,
) -> Result<String> {
    // Validate password strength
    if request.password.len() < 8 {
        return Err(Error::Crypto("Password must be at least 8 characters".to_string()));
    }

    // Set up data directory
    let app_data_dir = app.path().app_data_dir()
        .map_err(|e| Error::Internal(format!("Failed to get app data dir: {}", e)))?;
    state.set_data_dir(app_data_dir).await?;

    // Import wallet with encryption (testnet by default for safety)
    let address = state.import(&request.mnemonic, &request.password, true).await?;

    Ok(address)
}

/// Unlock an existing wallet
#[tauri::command]
pub async fn unlock_wallet(
    app: AppHandle,
    state: State<'_, WalletState>,
    password: String,
) -> Result<bool> {
    // Set up data directory
    let app_data_dir = app.path().app_data_dir()
        .map_err(|e| Error::Internal(format!("Failed to get app data dir: {}", e)))?;
    state.set_data_dir(app_data_dir).await?;

    // Load wallet metadata from file
    state.load_metadata().await?;

    // Decrypt and unlock
    state.unlock(&password).await?;

    Ok(true)
}

/// Lock the wallet (clear sensitive data from memory)
#[tauri::command]
pub async fn lock_wallet(state: State<'_, WalletState>) -> Result<()> {
    state.lock().await;
    Ok(())
}

/// Wallet info returned to frontend
#[derive(Debug, Serialize)]
pub struct WalletInfo {
    pub locked: bool,
    pub address_count: usize,
    pub network: Option<String>,
}

/// Get wallet information
#[tauri::command]
pub async fn get_wallet_info(state: State<'_, WalletState>) -> Result<WalletInfo> {
    let locked = !state.is_unlocked().await;
    let addresses = state.addresses.read().await;
    let connection = state.connection.read().await;

    Ok(WalletInfo {
        locked,
        address_count: addresses.len(),
        network: connection.as_ref().map(|c| c.network.clone()),
    })
}

/// Export the mnemonic phrase (requires unlock)
#[tauri::command]
pub async fn export_mnemonic(
    state: State<'_, WalletState>,
    password: String,
) -> Result<String> {
    if !state.is_unlocked().await {
        return Err(Error::WalletLocked);
    }
    // TODO: Re-verify password and return mnemonic
    Err(Error::Internal("Not implemented".to_string()))
}

// ============================================================================
// Address & Balance Commands
// ============================================================================

/// Get all addresses in the wallet
#[tauri::command]
pub async fn get_addresses(state: State<'_, WalletState>) -> Result<Vec<WalletAddress>> {
    let addresses = state.addresses.read().await;
    Ok(addresses.clone())
}

/// Generate a new receive address
#[tauri::command]
pub async fn generate_address(
    state: State<'_, WalletState>,
    label: Option<String>,
) -> Result<WalletAddress> {
    // Use wallet state's generate_address which handles crypto properly
    state.generate_address(label, false).await
}

/// Balance response
#[derive(Debug, Serialize)]
pub struct BalanceResponse {
    /// Balance in sompi (1 SYN = 100_000_000 sompi)
    pub balance: u64,
    /// Human-readable balance
    pub balance_human: String,
    /// Pending incoming
    pub pending: u64,
}

/// Get wallet balance
#[tauri::command]
pub async fn get_balance(state: State<'_, WalletState>) -> Result<BalanceResponse> {
    // TODO: Query node for UTXOs and sum balance
    Ok(BalanceResponse {
        balance: 0,
        balance_human: "0 SYN".to_string(),
        pending: 0,
    })
}

/// UTXO response
#[derive(Debug, Serialize)]
pub struct UtxoResponse {
    pub txid: String,
    pub vout: u32,
    pub amount: u64,
    pub confirmations: u64,
}

/// Get UTXOs for the wallet
#[tauri::command]
pub async fn get_utxos(state: State<'_, WalletState>) -> Result<Vec<UtxoResponse>> {
    // TODO: Query node for UTXOs
    Ok(vec![])
}

// ============================================================================
// Transaction Commands
// ============================================================================

/// Transaction creation request
#[derive(Debug, Deserialize)]
pub struct CreateTransactionRequest {
    pub to: String,
    pub amount: u64,
    pub fee: Option<u64>,
    pub use_dilithium: bool,
}

/// Unsigned transaction response
#[derive(Debug, Serialize)]
pub struct UnsignedTransaction {
    pub tx_hex: String,
    pub fee: u64,
    pub inputs: Vec<UtxoResponse>,
}

/// Create an unsigned transaction
#[tauri::command]
pub async fn create_transaction(
    state: State<'_, WalletState>,
    request: CreateTransactionRequest,
) -> Result<UnsignedTransaction> {
    if !state.is_unlocked().await {
        return Err(Error::WalletLocked);
    }

    // TODO: Select UTXOs, build transaction
    Err(Error::Internal("Not implemented".to_string()))
}

/// Signed transaction response
#[derive(Debug, Serialize)]
pub struct SignedTransaction {
    pub tx_hex: String,
    pub txid: String,
}

/// Sign a transaction
#[tauri::command]
pub async fn sign_transaction(
    state: State<'_, WalletState>,
    tx_hex: String,
) -> Result<SignedTransaction> {
    if !state.is_unlocked().await {
        return Err(Error::WalletLocked);
    }

    // TODO: Sign transaction with appropriate key
    Err(Error::Internal("Not implemented".to_string()))
}

/// Broadcast response
#[derive(Debug, Serialize)]
pub struct BroadcastResponse {
    pub txid: String,
    pub accepted: bool,
}

/// Broadcast a signed transaction
#[tauri::command]
pub async fn broadcast_transaction(
    state: State<'_, WalletState>,
    tx_hex: String,
) -> Result<BroadcastResponse> {
    let connection = state.connection.read().await;
    if connection.is_none() {
        return Err(Error::Network("Not connected to node".to_string()));
    }

    // TODO: Submit transaction via RPC
    Err(Error::Internal("Not implemented".to_string()))
}

/// Transaction history entry
#[derive(Debug, Serialize)]
pub struct TransactionHistoryEntry {
    pub txid: String,
    pub direction: String, // "sent" or "received"
    pub amount: u64,
    pub fee: Option<u64>,
    pub timestamp: i64,
    pub confirmations: u64,
    pub counterparty: Option<String>,
}

/// Get transaction history
#[tauri::command]
pub async fn get_transaction_history(
    state: State<'_, WalletState>,
    limit: Option<usize>,
) -> Result<Vec<TransactionHistoryEntry>> {
    // TODO: Query indexed transactions
    Ok(vec![])
}

// ============================================================================
// Network Commands
// ============================================================================

/// Connect to a Synor node
#[tauri::command]
pub async fn connect_node(
    state: State<'_, WalletState>,
    rpc_url: String,
    ws_url: Option<String>,
) -> Result<NetworkConnection> {
    // TODO: Test connection, get network info
    let network = if rpc_url.contains("testnet") || rpc_url.contains("17110") {
        "testnet"
    } else {
        "mainnet"
    };

    let connection = NetworkConnection {
        rpc_url,
        ws_url,
        connected: true,
        network: network.to_string(),
    };

    let mut conn = state.connection.write().await;
    *conn = Some(connection.clone());

    Ok(connection)
}

/// Disconnect from the current node
#[tauri::command]
pub async fn disconnect_node(state: State<'_, WalletState>) -> Result<()> {
    let mut connection = state.connection.write().await;
    *connection = None;
    Ok(())
}

/// Network status
#[derive(Debug, Serialize)]
pub struct NetworkStatus {
    pub connected: bool,
    pub network: Option<String>,
    pub block_height: Option<u64>,
    pub peer_count: Option<u32>,
    pub synced: Option<bool>,
}

/// Get network status
#[tauri::command]
pub async fn get_network_status(state: State<'_, WalletState>) -> Result<NetworkStatus> {
    let connection = state.connection.read().await;

    if let Some(conn) = connection.as_ref() {
        // TODO: Query node for actual status
        Ok(NetworkStatus {
            connected: conn.connected,
            network: Some(conn.network.clone()),
            block_height: None,
            peer_count: None,
            synced: None,
        })
    } else {
        Ok(NetworkStatus {
            connected: false,
            network: None,
            block_height: None,
            peer_count: None,
            synced: None,
        })
    }
}
