from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any


@dataclass(frozen=True)
class PolicyDecision:
    """A policy evaluation decision attached to a spend intent or payment."""

    allowed: bool
    reason: str | None = None
    rules_evaluated: int | None = None
    rules_matched: list[str] = field(default_factory=list)

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> PolicyDecision:
        return cls(
            allowed=data["allowed"],
            reason=data.get("reason"),
            rules_evaluated=data.get("rules_evaluated"),
            rules_matched=data.get("rules_matched", []),
        )


@dataclass(frozen=True)
class SpendIntent:
    """Represents a declared spending intent awaiting approval."""

    id: str
    status: str
    goal: str
    budget: float
    currency: str
    merchant: str | None = None
    category: str | None = None
    domain: str | None = None
    spend_token: str | None = None
    policy_decision: PolicyDecision | None = None
    metadata: dict[str, Any] = field(default_factory=dict)
    created_at: str | None = None
    updated_at: str | None = None

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> SpendIntent:
        policy_raw = data.get("policy_decision")
        return cls(
            id=data["id"],
            status=data["status"],
            goal=data["goal"],
            budget=data["budget"],
            currency=data["currency"],
            merchant=data.get("merchant"),
            category=data.get("category"),
            domain=data.get("domain"),
            spend_token=data.get("spend_token"),
            policy_decision=PolicyDecision.from_dict(policy_raw) if policy_raw else None,
            metadata=data.get("metadata", {}),
            created_at=data.get("created_at"),
            updated_at=data.get("updated_at"),
        )


@dataclass(frozen=True)
class PaymentRequest:
    """Represents a payment request created for execution."""

    id: str
    status: str
    amount: float
    merchant: str
    domain: str | None = None
    category: str | None = None
    reason: str | None = None
    evidence_links: list[str] = field(default_factory=list)
    spend_token: str | None = None
    policy_decision: PolicyDecision | None = None
    created_at: str | None = None
    updated_at: str | None = None

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> PaymentRequest:
        policy_raw = data.get("policy_decision")
        return cls(
            id=data["id"],
            status=data["status"],
            amount=data["amount"],
            merchant=data["merchant"],
            domain=data.get("domain"),
            category=data.get("category"),
            reason=data.get("reason"),
            evidence_links=data.get("evidence_links", []),
            spend_token=data.get("spend_token"),
            policy_decision=PolicyDecision.from_dict(policy_raw) if policy_raw else None,
            created_at=data.get("created_at"),
            updated_at=data.get("updated_at"),
        )


@dataclass(frozen=True)
class ExecuteResult:
    """Result of executing a spend intent or payment."""

    id: str
    status: str
    amount: float
    currency: str
    merchant: str | None = None
    transaction_id: str | None = None
    executed_at: str | None = None

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> ExecuteResult:
        return cls(
            id=data["id"],
            status=data["status"],
            amount=data["amount"],
            currency=data["currency"],
            merchant=data.get("merchant"),
            transaction_id=data.get("transaction_id"),
            executed_at=data.get("executed_at"),
        )


@dataclass(frozen=True)
class AgentBudget:
    """Budget information for an agent."""

    agent_id: str
    total_budget: float
    spent: float
    remaining: float
    currency: str
    period: str | None = None
    resets_at: str | None = None

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> AgentBudget:
        return cls(
            agent_id=data["agent_id"],
            total_budget=data["total_budget"],
            spent=data["spent"],
            remaining=data["remaining"],
            currency=data["currency"],
            period=data.get("period"),
            resets_at=data.get("resets_at"),
        )
