"""
Synor Privacy SDK Types

Confidential transactions, ring signatures, stealth addresses, and commitments.
"""

from dataclasses import dataclass, field
from typing import Optional, List, Dict, Any, Literal


# ==================== Config Types ====================

DEFAULT_PRIVACY_ENDPOINT = "https://privacy.synor.cc/api/v1"


@dataclass
class PrivacyConfig:
    """Privacy SDK configuration."""
    api_key: str
    endpoint: str = DEFAULT_PRIVACY_ENDPOINT
    timeout: float = 30.0
    retries: int = 3
    debug: bool = False


class PrivacyError(Exception):
    """Privacy-specific error."""

    def __init__(
        self,
        message: str,
        code: Optional[str] = None,
        status_code: Optional[int] = None,
        details: Optional[Dict[str, Any]] = None,
    ):
        super().__init__(message)
        self.message = message
        self.code = code
        self.status_code = status_code
        self.details = details or {}


# ==================== Key Types ====================

KeyType = Literal["ed25519", "secp256k1"]


@dataclass
class PublicKey:
    """Public key representation."""
    key: str
    type: KeyType

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "PublicKey":
        return cls(
            key=data["key"],
            type=data["type"],
        )


@dataclass
class PrivateKey:
    """Private key representation (for signing operations)."""
    key: str
    type: KeyType

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "PrivateKey":
        return cls(
            key=data["key"],
            type=data["type"],
        )


# ==================== Confidential Transaction Types ====================

@dataclass
class ConfidentialUTXO:
    """UTXO for confidential transaction input."""
    txid: str
    vout: int
    commitment: str
    range_proof: str
    blinding: Optional[str] = None
    amount: Optional[str] = None

    def to_dict(self) -> Dict[str, Any]:
        d = {
            "txid": self.txid,
            "vout": self.vout,
            "commitment": self.commitment,
            "rangeProof": self.range_proof,
        }
        if self.blinding:
            d["blinding"] = self.blinding
        if self.amount:
            d["amount"] = self.amount
        return d


@dataclass
class ConfidentialOutput:
    """Output for confidential transaction."""
    recipient: str
    amount: str
    blinding: Optional[str] = None

    def to_dict(self) -> Dict[str, Any]:
        d = {
            "recipient": self.recipient,
            "amount": self.amount,
        }
        if self.blinding:
            d["blinding"] = self.blinding
        return d


@dataclass
class OutputFeatures:
    """Output features for confidential transactions."""
    flags: int
    lock_height: Optional[int] = None

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "OutputFeatures":
        return cls(
            flags=data["flags"],
            lock_height=data.get("lockHeight", data.get("lock_height")),
        )


@dataclass
class ConfidentialTxInput:
    """Confidential transaction input."""
    output_ref: str
    commitment: str

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "ConfidentialTxInput":
        return cls(
            output_ref=data.get("outputRef", data.get("output_ref", "")),
            commitment=data["commitment"],
        )


@dataclass
class ConfidentialTxOutput:
    """Confidential transaction output."""
    commitment: str
    range_proof: str
    features: OutputFeatures

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "ConfidentialTxOutput":
        return cls(
            commitment=data["commitment"],
            range_proof=data.get("rangeProof", data.get("range_proof", "")),
            features=OutputFeatures.from_dict(data["features"]),
        )


@dataclass
class TransactionKernel:
    """Transaction kernel for confidential transactions."""
    features: int
    fee: str
    lock_height: int
    excess: str
    excess_signature: str

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "TransactionKernel":
        return cls(
            features=data["features"],
            fee=data["fee"],
            lock_height=data.get("lockHeight", data.get("lock_height", 0)),
            excess=data["excess"],
            excess_signature=data.get("excessSignature", data.get("excess_signature", "")),
        )


@dataclass
class ConfidentialTransaction:
    """Confidential transaction."""
    txid: str
    version: int
    inputs: List[ConfidentialTxInput]
    outputs: List[ConfidentialTxOutput]
    kernel: TransactionKernel
    offset: str
    raw: str

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "ConfidentialTransaction":
        return cls(
            txid=data["txid"],
            version=data["version"],
            inputs=[ConfidentialTxInput.from_dict(i) for i in data.get("inputs", [])],
            outputs=[ConfidentialTxOutput.from_dict(o) for o in data.get("outputs", [])],
            kernel=TransactionKernel.from_dict(data["kernel"]),
            offset=data["offset"],
            raw=data["raw"],
        )


@dataclass
class VerifyConfidentialTxDetails:
    """Verification details for confidential transaction."""
    commitments_balance: bool
    range_proofs_valid: bool
    signature_valid: bool
    no_duplicate_inputs: bool

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "VerifyConfidentialTxDetails":
        return cls(
            commitments_balance=data.get("commitmentsBalance", data.get("commitments_balance", False)),
            range_proofs_valid=data.get("rangeProofsValid", data.get("range_proofs_valid", False)),
            signature_valid=data.get("signatureValid", data.get("signature_valid", False)),
            no_duplicate_inputs=data.get("noDuplicateInputs", data.get("no_duplicate_inputs", False)),
        )


@dataclass
class VerifyConfidentialTxResult:
    """Confidential transaction verification result."""
    valid: bool
    details: VerifyConfidentialTxDetails
    error: Optional[str] = None

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "VerifyConfidentialTxResult":
        return cls(
            valid=data["valid"],
            details=VerifyConfidentialTxDetails.from_dict(data["details"]),
            error=data.get("error"),
        )


# ==================== Ring Signature Types ====================

@dataclass
class RingSignatureComponents:
    """Ring signature components."""
    c: List[str]
    r: List[str]

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "RingSignatureComponents":
        return cls(
            c=data["c"],
            r=data["r"],
        )


@dataclass
class RingSignature:
    """Ring signature."""
    id: str
    message_hash: str
    ring: List[str]
    key_image: str
    signature: RingSignatureComponents
    ring_size: int

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "RingSignature":
        return cls(
            id=data["id"],
            message_hash=data.get("messageHash", data.get("message_hash", "")),
            ring=data["ring"],
            key_image=data.get("keyImage", data.get("key_image", "")),
            signature=RingSignatureComponents.from_dict(data["signature"]),
            ring_size=data.get("ringSize", data.get("ring_size", 0)),
        )

    def to_dict(self) -> Dict[str, Any]:
        return {
            "id": self.id,
            "messageHash": self.message_hash,
            "ring": self.ring,
            "keyImage": self.key_image,
            "signature": {
                "c": self.signature.c,
                "r": self.signature.r,
            },
            "ringSize": self.ring_size,
        }


@dataclass
class VerifyRingSignatureResult:
    """Ring signature verification result."""
    valid: bool
    key_image: str

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "VerifyRingSignatureResult":
        return cls(
            valid=data["valid"],
            key_image=data.get("keyImage", data.get("key_image", "")),
        )


# ==================== Stealth Address Types ====================

@dataclass
class StealthAddress:
    """Stealth address."""
    address: str
    scan_public_key: str
    spend_public_key: str

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "StealthAddress":
        return cls(
            address=data["address"],
            scan_public_key=data.get("scanPublicKey", data.get("scan_public_key", "")),
            spend_public_key=data.get("spendPublicKey", data.get("spend_public_key", "")),
        )


@dataclass
class StealthKeypair:
    """Stealth address keypair."""
    address: StealthAddress
    scan_private_key: str
    spend_private_key: str

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "StealthKeypair":
        return cls(
            address=StealthAddress.from_dict(data["address"]),
            scan_private_key=data.get("scanPrivateKey", data.get("scan_private_key", "")),
            spend_private_key=data.get("spendPrivateKey", data.get("spend_private_key", "")),
        )


@dataclass
class OneTimeAddress:
    """One-time address derived from stealth address."""
    address: str
    ephemeral_public_key: str
    shared_secret: Optional[str] = None

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "OneTimeAddress":
        return cls(
            address=data["address"],
            ephemeral_public_key=data.get("ephemeralPublicKey", data.get("ephemeral_public_key", "")),
            shared_secret=data.get("sharedSecret", data.get("shared_secret")),
        )


@dataclass
class SharedSecret:
    """Shared secret result."""
    secret: str
    one_time_private_key: str
    one_time_address: str

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "SharedSecret":
        return cls(
            secret=data["secret"],
            one_time_private_key=data.get("oneTimePrivateKey", data.get("one_time_private_key", "")),
            one_time_address=data.get("oneTimeAddress", data.get("one_time_address", "")),
        )


# ==================== Commitment Types ====================

GeneratorType = Literal["default", "alternate"]


@dataclass
class Commitment:
    """Pedersen commitment."""
    commitment: str
    generator: GeneratorType

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "Commitment":
        return cls(
            commitment=data["commitment"],
            generator=data.get("generator", "default"),
        )


@dataclass
class CommitmentWithBlinding:
    """Commitment with blinding factor."""
    commitment: Commitment
    blinding: str

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "CommitmentWithBlinding":
        return cls(
            commitment=Commitment.from_dict(data["commitment"]),
            blinding=data["blinding"],
        )


# ==================== Range Proof Types ====================

@dataclass
class RangeProof:
    """Bulletproof range proof."""
    proof: str
    commitment: str
    bit_length: int

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "RangeProof":
        return cls(
            proof=data["proof"],
            commitment=data["commitment"],
            bit_length=data.get("bitLength", data.get("bit_length", 64)),
        )


@dataclass
class VerifyRangeProofResult:
    """Range proof verification result."""
    valid: bool
    min_value: str
    max_value: str

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "VerifyRangeProofResult":
        return cls(
            valid=data["valid"],
            min_value=data.get("minValue", data.get("min_value", "0")),
            max_value=data.get("maxValue", data.get("max_value", "")),
        )
