from typing import Dict, List, Optional, Union
from decimal import Decimal
from pydantic import BaseModel, Field

class AddressValidation(BaseModel):
    """Model for 'validateaddress' response"""
    isvalid: bool = Field(..., description="If the address is valid")
    address: Optional[str] = Field(None, description="The evrmore address validated")
    scriptPubKey: Optional[str] = Field(None, description="The hex-encoded scriptPubKey generated by the address")
    ismine: Optional[bool] = Field(None, description="If the address is yours")
    iswatchonly: Optional[bool] = Field(None, description="If the address is watchonly")
    isscript: Optional[bool] = Field(None, description="If the key is a script")
    script: Optional[str] = Field(None, description="The script type")
    hex: Optional[str] = Field(None, description="The redeemscript for the p2sh address")
    addresses: Optional[List[str]] = Field(None, description="List of addresses associated with the script")
    sigsrequired: Optional[int] = Field(None, description="Number of signatures required to spend multisig output")
    pubkey: Optional[str] = Field(None, description="The hex value of the raw public key")
    iscompressed: Optional[bool] = Field(None, description="If the address is compressed")
    account: Optional[str] = Field(None, description="DEPRECATED. The account associated with the address")
    timestamp: Optional[int] = Field(None, description="The creation time of the key if available")
    hdkeypath: Optional[str] = Field(None, description="The HD keypath if the key is HD and available")
    hdmasterkeyid: Optional[str] = Field(None, description="The HD master key id if the key is HD and available")

class SmartFeeEstimate(BaseModel):
    """Model for 'estimatesmartfee' response"""
    feerate: Optional[Decimal] = Field(None, description="The estimated fee rate in EVR/kB")
    errors: Optional[List[str]] = Field(None, description="Errors encountered during processing")
    blocks: int = Field(..., description="The block number where the estimate was found")

def wrap_util_commands(client):
    """Add typed utility commands to the client."""
    
    def createmultisig(
        nrequired: int,
        keys: List[str]
    ) -> Dict[str, str]:
        """Create a multi-signature address."""
        return client.execute_command("createmultisig", nrequired, keys)
    
    def estimatefee(nblocks: int) -> Decimal:
        """DEPRECATED. Estimate fee rate in EVR/kB."""
        result = client.execute_command("estimatefee", nblocks)
        return Decimal(str(result))
    
    def estimatesmartfee(
        conf_target: int,
        estimate_mode: str = "CONSERVATIVE"
    ) -> SmartFeeEstimate:
        """Estimate fee rate in EVR/kB."""
        result = client.execute_command("estimatesmartfee", conf_target, estimate_mode)
        return SmartFeeEstimate.model_validate(result)
    
    def signmessagewithprivkey(privkey: str, message: str) -> str:
        """Sign a message with a private key."""
        return client.execute_command("signmessagewithprivkey", privkey, message)
    
    def validateaddress(address: str) -> AddressValidation:
        """Validate an Evrmore address."""
        result = client.execute_command("validateaddress", address)
        return AddressValidation.model_validate(result)
    
    def verifymessage(address: str, signature: str, message: str) -> bool:
        """Verify a signed message."""
        return client.execute_command("verifymessage", address, signature, message)
    
    # Add methods to client
    client.createmultisig = createmultisig
    client.estimatefee = estimatefee
    client.estimatesmartfee = estimatesmartfee
    client.signmessagewithprivkey = signmessagewithprivkey
    client.validateaddress = validateaddress
    client.verifymessage = verifymessage
    
    return client 