//! Address commands.

use anyhow::Result;

use crate::output::{self, OutputFormat};

/// Validate an address.
pub async fn validate(address: &str, format: OutputFormat) -> Result<()> {
    let validation = validate_address(address);

    match format {
        OutputFormat::Json => {
            let result = serde_json::json!({
                "address": address,
                "valid": validation.is_valid,
                "network": validation.network,
                "type": validation.address_type,
                "error": validation.error,
            });
            println!("{}", serde_json::to_string_pretty(&result)?);
        }
        OutputFormat::Text => {
            if validation.is_valid {
                output::print_success("Address is valid");
                output::print_kv(
                    "Network",
                    validation.network.as_deref().unwrap_or("unknown"),
                );
                output::print_kv(
                    "Type",
                    validation.address_type.as_deref().unwrap_or("unknown"),
                );
            } else {
                output::print_error(&format!(
                    "Invalid address: {}",
                    validation
                        .error
                        .unwrap_or_else(|| "unknown error".to_string())
                ));
            }
        }
    }

    Ok(())
}

/// Decode an address.
pub async fn decode(address: &str, format: OutputFormat) -> Result<()> {
    let decoded = decode_address(address)?;

    match format {
        OutputFormat::Json => {
            let result = serde_json::json!({
                "address": address,
                "prefix": decoded.prefix,
                "version": decoded.version,
                "public_key_hash": decoded.public_key_hash,
                "checksum": decoded.checksum,
            });
            println!("{}", serde_json::to_string_pretty(&result)?);
        }
        OutputFormat::Text => {
            output::print_header("Address Decode");
            output::print_kv("Prefix", &decoded.prefix);
            output::print_kv("Version", &decoded.version.to_string());
            output::print_kv("Public Key Hash", &decoded.public_key_hash);
            output::print_kv("Checksum", &decoded.checksum);
        }
    }

    Ok(())
}

// ==================== Helpers ====================

#[derive(Debug)]
struct AddressValidation {
    is_valid: bool,
    network: Option<String>,
    address_type: Option<String>,
    error: Option<String>,
}

fn validate_address(address: &str) -> AddressValidation {
    // Check prefix
    if let Some(rest) = address.strip_prefix("synor:") {
        // Check length (40 hex chars = 20 bytes public key hash)
        if rest.len() != 40 {
            return AddressValidation {
                is_valid: false,
                network: None,
                address_type: None,
                error: Some("Invalid length".to_string()),
            };
        }

        // Check if valid hex
        if hex::decode(rest).is_err() {
            return AddressValidation {
                is_valid: false,
                network: None,
                address_type: None,
                error: Some("Invalid hex encoding".to_string()),
            };
        }

        AddressValidation {
            is_valid: true,
            network: Some("mainnet".to_string()),
            address_type: Some("Ed25519".to_string()),
            error: None,
        }
    } else if let Some(rest) = address.strip_prefix("synorq:") {
        // Quantum-resistant address
        if rest.len() < 40 {
            return AddressValidation {
                is_valid: false,
                network: None,
                address_type: None,
                error: Some("Invalid length".to_string()),
            };
        }

        AddressValidation {
            is_valid: true,
            network: Some("mainnet".to_string()),
            address_type: Some("Dilithium".to_string()),
            error: None,
        }
    } else if address.starts_with("synorh:") {
        // Hybrid address
        AddressValidation {
            is_valid: true,
            network: Some("mainnet".to_string()),
            address_type: Some("Hybrid".to_string()),
            error: None,
        }
    } else if address.starts_with("tsynor:") {
        // Testnet
        AddressValidation {
            is_valid: true,
            network: Some("testnet".to_string()),
            address_type: Some("Ed25519".to_string()),
            error: None,
        }
    } else {
        AddressValidation {
            is_valid: false,
            network: None,
            address_type: None,
            error: Some("Unknown address prefix".to_string()),
        }
    }
}

#[derive(Debug)]
struct DecodedAddress {
    prefix: String,
    version: u8,
    public_key_hash: String,
    checksum: String,
}

fn decode_address(address: &str) -> Result<DecodedAddress> {
    // Split prefix
    let parts: Vec<&str> = address.splitn(2, ':').collect();
    if parts.len() != 2 {
        anyhow::bail!("Invalid address format");
    }

    let prefix = parts[0].to_string();
    let data = parts[1];

    // Decode hex
    let bytes = hex::decode(data)?;

    if bytes.is_empty() {
        anyhow::bail!("Empty address data");
    }

    // Extract components
    let version = if prefix == "synor" {
        0
    } else if prefix == "synorq" {
        1
    } else if prefix == "synorh" {
        2
    } else {
        3
    };

    // Calculate checksum
    let checksum_input = format!("{}:{}", prefix, data);
    let checksum: [u8; 32] = blake3::hash(checksum_input.as_bytes()).into();

    Ok(DecodedAddress {
        prefix,
        version,
        public_key_hash: hex::encode(&bytes),
        checksum: hex::encode(&checksum[..4]),
    })
}
