"""Purchases services."""

from __future__ import annotations

from dataclasses import dataclass, field

from ..common.value_objects import Money
from .entities import PurchaseOrder
from .exceptions import InvalidPurchaseOrderError
from .policies import DefaultPurchaseApprovalPolicy, DefaultPurchaseOrderTransitionPolicy, PurchaseApprovalPolicy, PurchaseOrderTransitionPolicy


@dataclass(frozen=True)
class PurchasePricingService:
    def calculate_subtotal(self, order: PurchaseOrder) -> Money:
        return order.amount_untaxed

    def calculate_discount(self, order: PurchaseOrder) -> Money:
        return order.amount_discount

    def calculate_tax(self, order: PurchaseOrder) -> Money:
        return order.amount_tax

    def calculate_total(self, order: PurchaseOrder) -> Money:
        return order.amount_total


@dataclass
class PurchaseWorkflowService:
    transition_policy: PurchaseOrderTransitionPolicy = field(default_factory=DefaultPurchaseOrderTransitionPolicy)
    approval_policy: PurchaseApprovalPolicy = field(default_factory=DefaultPurchaseApprovalPolicy)
    pricing_service: PurchasePricingService = field(default_factory=PurchasePricingService)

    def send_rfq(self, order: PurchaseOrder) -> PurchaseOrder:
        self._validate_order(order)
        order.send_rfq(policy=self.transition_policy)
        return order

    def confirm(self, order: PurchaseOrder) -> PurchaseOrder:
        self._validate_order(order)
        order.confirm(approval_policy=self.approval_policy, policy=self.transition_policy)
        return order

    def approve(self, order: PurchaseOrder) -> PurchaseOrder:
        self._validate_order(order)
        order.approve(policy=self.transition_policy)
        return order

    def receive(self, order: PurchaseOrder) -> PurchaseOrder:
        self._validate_order(order)
        order.receive(policy=self.transition_policy)
        return order

    def cancel(self, order: PurchaseOrder) -> PurchaseOrder:
        self._validate_order(order)
        order.cancel(policy=self.transition_policy)
        return order

    def amounts(self, order: PurchaseOrder) -> dict[str, object]:
        self._validate_order(order)
        return {
            "subtotal": self.pricing_service.calculate_subtotal(order),
            "discount": self.pricing_service.calculate_discount(order),
            "tax": self.pricing_service.calculate_tax(order),
            "total": self.pricing_service.calculate_total(order),
            "state": order.state,
        }

    def _validate_order(self, order: PurchaseOrder) -> None:
        if not isinstance(order, PurchaseOrder):
            raise InvalidPurchaseOrderError("order must be a PurchaseOrder instance")
