"""Bitcoin network operations using bit library."""
import logging
from typing import Optional

logger = logging.getLogger(__name__)


class BitcoinService:
    """
    Service for Bitcoin network operations.
    Handles address generation, balance checking, and transactions.
    """

    def __init__(self, testnet: bool = True):
        """
        Initialize Bitcoin service.

        Args:
            testnet: If True, use testnet; otherwise use mainnet.
        """
        self.testnet = testnet

    def _get_key_class(self):
        """Get the appropriate key class based on network."""
        from bit import Key, PrivateKeyTestnet
        return PrivateKeyTestnet if self.testnet else Key

    def generate_keypair(self) -> dict:
        """
        Generate new Bitcoin keypair.

        Returns:
            Dict with 'address', 'public_key', and 'private_key' (WIF format).
        """
        key_class = self._get_key_class()
        key = key_class()
        return {
            'address': key.address,
            'public_key': key.public_key.hex(),
            'private_key': key.to_wif()  # Wallet Import Format
        }

    def get_balance(self, address: str) -> int:
        """
        Get balance in satoshis from blockchain.

        Args:
            address: Bitcoin address to check.

        Returns:
            Balance in satoshis, or 0 on error.
        """
        try:
            from bit.network import NetworkAPI
            if self.testnet:
                balance = NetworkAPI.get_balance_testnet(address)
            else:
                balance = NetworkAPI.get_balance(address)
            return balance
        except Exception as e:
            logger.error(f"Failed to fetch balance for {address}: {e}")
            return 0

    def get_unspent(self, address: str) -> list:
        """
        Get unspent transaction outputs for address.

        Args:
            address: Bitcoin address to check.

        Returns:
            List of UTXOs, or empty list on error.
        """
        try:
            from bit.network import NetworkAPI
            if self.testnet:
                return NetworkAPI.get_unspent_testnet(address)
            return NetworkAPI.get_unspent(address)
        except Exception as e:
            logger.error(f"Failed to fetch UTXOs for {address}: {e}")
            return []

    def send_transaction(self, private_key_wif: str, to_address: str,
                         amount_satoshis: int) -> Optional[str]:
        """
        Send BTC transaction.

        Args:
            private_key_wif: Sender's private key in WIF format.
            to_address: Recipient's Bitcoin address.
            amount_satoshis: Amount to send in satoshis.

        Returns:
            Transaction hash on success, None on failure.
        """
        try:
            key_class = self._get_key_class()
            key = key_class(private_key_wif)
            tx_hash = key.send([(to_address, amount_satoshis, 'satoshi')])
            logger.info(f"Sent {amount_satoshis} satoshis to {to_address}: {tx_hash}")
            return tx_hash
        except Exception as e:
            logger.error(f"Failed to send transaction: {e}")
            return None

    def validate_address(self, address: str) -> bool:
        """
        Validate Bitcoin address format and checksum.

        Args:
            address: Address string to validate.

        Returns:
            True if valid for this network, False otherwise.
        """
        if not address or not isinstance(address, str):
            return False

        try:
            address = address.strip()

            if self.testnet:
                # Testnet addresses: m/n (legacy), 2 (P2SH), tb1 (bech32)
                if address.startswith(('m', 'n', '2')):
                    # Base58 testnet address
                    return 26 <= len(address) <= 35
                elif address.startswith('tb1'):
                    # Bech32 testnet address
                    return 42 <= len(address) <= 62
                return False
            else:
                # Mainnet addresses: 1 (legacy), 3 (P2SH), bc1 (bech32)
                if address.startswith(('1', '3')):
                    # Base58 mainnet address
                    return 26 <= len(address) <= 35
                elif address.startswith('bc1'):
                    # Bech32 mainnet address
                    return 42 <= len(address) <= 62
                return False

        except Exception:
            return False

    def estimate_fee(self, num_inputs: int = 1, num_outputs: int = 2) -> int:
        """
        Estimate transaction fee in satoshis.

        Args:
            num_inputs: Number of transaction inputs.
            num_outputs: Number of transaction outputs.

        Returns:
            Estimated fee in satoshis.
        """
        # Rough estimate: ~148 bytes per input, ~34 bytes per output, ~10 overhead
        tx_size = (num_inputs * 148) + (num_outputs * 34) + 10
        # Use a reasonable fee rate (satoshis per byte)
        # Could be made dynamic based on network conditions
        fee_rate = 10
        return tx_size * fee_rate
