"""Purchases policies."""

from __future__ import annotations

from dataclasses import dataclass
from decimal import Decimal
from typing import Protocol

from ..common.value_objects import Money
from .enums import PurchaseOrderState
from .exceptions import InvalidPurchaseTransitionError


class PurchaseApprovalPolicy(Protocol):
    def requires_approval(self, amount_total: Money) -> bool: ...


@dataclass(frozen=True)
class DefaultPurchaseApprovalPolicy:
    approval_threshold: Decimal = Decimal("5000000")

    def requires_approval(self, amount_total: Money) -> bool:
        if not isinstance(amount_total, Money):
            raise TypeError("amount_total must be a Money instance")
        return amount_total.amount >= self.approval_threshold


class PurchaseOrderTransitionPolicy(Protocol):
    def can_transition(self, current: PurchaseOrderState, target: PurchaseOrderState) -> bool: ...
    def ensure_transition(self, current: PurchaseOrderState, target: PurchaseOrderState) -> None: ...


@dataclass(frozen=True)
class DefaultPurchaseOrderTransitionPolicy:
    def can_transition(self, current: PurchaseOrderState, target: PurchaseOrderState) -> bool:
        if not isinstance(current, PurchaseOrderState) or not isinstance(target, PurchaseOrderState):
            raise TypeError("current and target must be PurchaseOrderState instances")
        if current == target:
            return True
        if current in {PurchaseOrderState.DONE, PurchaseOrderState.CANCELLED}:
            return False
        if target == PurchaseOrderState.CANCELLED:
            return True
        if current == PurchaseOrderState.DRAFT and target in {PurchaseOrderState.RFQ_SENT, PurchaseOrderState.TO_APPROVE, PurchaseOrderState.PURCHASE}:
            return True
        if current == PurchaseOrderState.RFQ_SENT and target in {PurchaseOrderState.TO_APPROVE, PurchaseOrderState.PURCHASE}:
            return True
        if current == PurchaseOrderState.TO_APPROVE and target == PurchaseOrderState.PURCHASE:
            return True
        if current == PurchaseOrderState.PURCHASE and target == PurchaseOrderState.DONE:
            return True
        return False

    def ensure_transition(self, current: PurchaseOrderState, target: PurchaseOrderState) -> None:
        if not self.can_transition(current, target):
            raise InvalidPurchaseTransitionError(f"cannot move from {current.value} to {target.value}")
