"""
SCM Use Cases — Purchase Order Operations.

عملیات مدیریت سفارش خرید.
"""
from dataclasses import dataclass
from datetime import date
from decimal import Decimal
from uuid import uuid4

from ..dtos.scm_dtos import CreatePODTO, POResponseDTO
from ...domain.entities.purchase_order import (
    PurchaseOrder,
    PurchaseOrderLine,
    POStatus,
    POPriority,
)
from ...domain.repositories.interfaces import IPurchaseOrderRepository
from ...domain.exceptions import PONotFoundError, VendorBlockedError


@dataclass
class CreatePOUseCase:
    """Use Case — ایجاد سفارش خرید."""
    po_repo: IPurchaseOrderRepository

    def execute(self, dto: CreatePODTO, tenant_id=None) -> POResponseDTO:
        lines = []
        for idx, line_dto in enumerate(dto.lines, start=1):
            line = PurchaseOrderLine(
                id=uuid4(),
                tenant_id=tenant_id,
                order_id=None,
                line_number=idx,
                item_id=line_dto.item_id,
                item_code=line_dto.item_code,
                item_name=line_dto.item_name,
                description=line_dto.description,
                quantity=Decimal(line_dto.quantity),
                uom_id=line_dto.uom_id,
                uom_code=line_dto.uom_code,
                unit_price=Decimal(line_dto.unit_price),
                discount_percent=Decimal(line_dto.discount_percent),
                tax_percent=Decimal(line_dto.tax_percent),
                warehouse_id=line_dto.warehouse_id,
                warehouse_name=line_dto.warehouse_name,
                required_date=line_dto.required_date,
                pr_line_id=line_dto.pr_line_id,
                rfq_response_line_id=line_dto.rfq_response_line_id,
                notes=line_dto.notes,
            )
            lines.append(line)

        po = PurchaseOrder(
            id=uuid4(),
            tenant_id=tenant_id,
            po_number=dto.po_number,
            title=dto.title,
            description=dto.description,
            status=POStatus.DRAFT,
            priority=POPriority(dto.priority) if dto.priority else POPriority.NORMAL,
            vendor_id=dto.vendor_id,
            vendor_name=dto.vendor_name,
            vendor_code=dto.vendor_code,
            pr_id=dto.pr_id,
            pr_number=dto.pr_number,
            rfq_id=dto.rfq_id,
            rfq_number=dto.rfq_number,
            contract_id=dto.contract_id,
            buyer_id=dto.buyer_id,
            buyer_name=dto.buyer_name,
            expected_delivery_date=dto.expected_delivery_date,
            currency_code=dto.currency_code,
            payment_terms=dto.payment_terms,
            delivery_terms=dto.delivery_terms,
            shipping_address=dto.shipping_address,
            notes=dto.notes,
            lines=lines,
        )
        po.calculate_totals()

        saved = self.po_repo.save(po)

        return POResponseDTO(
            id=saved.id,
            po_number=saved.po_number,
            title=saved.title,
            status=saved.status.value if saved.status else "",
            priority=saved.priority.value if saved.priority else "",
            vendor_name=saved.vendor_name,
            vendor_code=saved.vendor_code,
            order_date=saved.order_date,
            expected_delivery_date=saved.expected_delivery_date,
            subtotal=str(saved.subtotal),
            total_discount=str(saved.total_discount),
            total_tax=str(saved.total_tax),
            total_amount=str(saved.total_amount),
            currency_code=saved.currency_code,
            buyer_name=saved.buyer_name,
            created_at=saved.created_at,
        )


@dataclass
class SubmitPOUseCase:
    """Use Case — ارسال سفارش برای تأیید."""
    po_repo: IPurchaseOrderRepository

    def execute(self, po_id) -> POResponseDTO:
        po = self.po_repo.get_by_id(po_id)
        if not po:
            raise PONotFoundError(str(po_id))

        po.submit()
        saved = self.po_repo.save(po)

        return POResponseDTO(
            id=saved.id,
            po_number=saved.po_number,
            title=saved.title,
            status=saved.status.value if saved.status else "",
        )


@dataclass
class ApprovePOUseCase:
    """Use Case — تأیید سفارش خرید."""
    po_repo: IPurchaseOrderRepository

    def execute(self, po_id, approved_by) -> POResponseDTO:
        po = self.po_repo.get_by_id(po_id)
        if not po:
            raise PONotFoundError(str(po_id))

        po.approve(approved_by)
        saved = self.po_repo.save(po)

        return POResponseDTO(
            id=saved.id,
            po_number=saved.po_number,
            title=saved.title,
            status=saved.status.value if saved.status else "",
        )


@dataclass
class RejectPOUseCase:
    """Use Case — رد سفارش خرید."""
    po_repo: IPurchaseOrderRepository

    def execute(self, po_id, reason: str = "") -> POResponseDTO:
        po = self.po_repo.get_by_id(po_id)
        if not po:
            raise PONotFoundError(str(po_id))

        po.reject(reason)
        saved = self.po_repo.save(po)

        return POResponseDTO(
            id=saved.id,
            po_number=saved.po_number,
            title=saved.title,
            status=saved.status.value if saved.status else "",
        )


@dataclass
class SendPOToVendorUseCase:
    """Use Case — ارسال سفارش به تأمین‌کننده."""
    po_repo: IPurchaseOrderRepository

    def execute(self, po_id) -> POResponseDTO:
        po = self.po_repo.get_by_id(po_id)
        if not po:
            raise PONotFoundError(str(po_id))

        po.send_to_vendor()
        saved = self.po_repo.save(po)

        return POResponseDTO(
            id=saved.id,
            po_number=saved.po_number,
            title=saved.title,
            status=saved.status.value if saved.status else "",
            order_date=saved.order_date,
        )


@dataclass
class CancelPOUseCase:
    """Use Case — لغو سفارش خرید."""
    po_repo: IPurchaseOrderRepository

    def execute(self, po_id) -> POResponseDTO:
        po = self.po_repo.get_by_id(po_id)
        if not po:
            raise PONotFoundError(str(po_id))

        po.cancel()
        saved = self.po_repo.save(po)

        return POResponseDTO(
            id=saved.id,
            po_number=saved.po_number,
            title=saved.title,
            status=saved.status.value if saved.status else "",
        )


@dataclass
class ClosePOUseCase:
    """Use Case — بستن سفارش خرید."""
    po_repo: IPurchaseOrderRepository

    def execute(self, po_id) -> POResponseDTO:
        po = self.po_repo.get_by_id(po_id)
        if not po:
            raise PONotFoundError(str(po_id))

        po.close()
        saved = self.po_repo.save(po)

        return POResponseDTO(
            id=saved.id,
            po_number=saved.po_number,
            title=saved.title,
            status=saved.status.value if saved.status else "",
        )
