from abc import ABC, abstractmethod
from decimal import Decimal

from app.domain.entities.sales import (
    Customer,
    SalesDelivery,
    SalesInvoice,
    SalesOrder,
    SalesPayment,
)
from app.domain.enums import (
    SalesDeliveryStatus,
    SalesInvoiceStatus,
    SalesOrderStatus,
    SalesPaymentStatus,
)


class SalesRepository(ABC):
    # ---- Customers ----
    @abstractmethod
    async def create_customer(self, customer: Customer) -> Customer:
        pass

    @abstractmethod
    async def get_customer(self, customer_id: str, company_id: str) -> Customer | None:
        pass

    @abstractmethod
    async def get_customer_by_code(self, company_id: str, code: str) -> Customer | None:
        pass

    @abstractmethod
    async def get_next_customer_code(self, company_id: str) -> str:
        pass

    @abstractmethod
    async def list_customers(
        self, company_id: str, is_active: bool | None = None, skip: int = 0, limit: int = 100
    ) -> list[Customer]:
        pass

    @abstractmethod
    async def count_customers(self, company_id: str, is_active: bool | None = None) -> int:
        pass

    @abstractmethod
    async def update_customer(self, customer_id: str, customer: Customer) -> Customer | None:
        pass

    @abstractmethod
    async def delete_customer(self, customer_id: str) -> bool:
        pass

    # ---- Sales orders ----
    @abstractmethod
    async def create_sales_order(self, order: SalesOrder) -> SalesOrder:
        pass

    @abstractmethod
    async def get_sales_order(self, order_id: str, company_id: str) -> SalesOrder | None:
        pass

    @abstractmethod
    async def list_sales_orders(
        self,
        company_id: str,
        status: SalesOrderStatus | None = None,
        customer_id: str | None = None,
        skip: int = 0,
        limit: int = 100,
    ) -> list[SalesOrder]:
        pass

    @abstractmethod
    async def count_sales_orders(
        self,
        company_id: str,
        status: SalesOrderStatus | None = None,
        customer_id: str | None = None,
    ) -> int:
        pass

    @abstractmethod
    async def update_sales_order(
        self, order_id: str, order: SalesOrder, *, replace_lines: bool = False
    ) -> SalesOrder | None:
        pass

    @abstractmethod
    async def update_so_line_quantities(
        self,
        line_id: str,
        *,
        reserved_quantity: Decimal | None = None,
        picked_quantity: Decimal | None = None,
        shipped_quantity: Decimal | None = None,
        invoiced_quantity: Decimal | None = None,
        available_quantity: Decimal | None = None,
        is_available: bool | None = None,
    ) -> None:
        pass

    @abstractmethod
    async def get_next_so_number(self, company_id: str) -> str:
        pass

    # ---- Deliveries ----
    @abstractmethod
    async def create_delivery(self, delivery: SalesDelivery) -> SalesDelivery:
        pass

    @abstractmethod
    async def get_delivery(self, delivery_id: str, company_id: str) -> SalesDelivery | None:
        pass

    @abstractmethod
    async def list_deliveries(
        self,
        company_id: str,
        status: SalesDeliveryStatus | None = None,
        sales_order_id: str | None = None,
        skip: int = 0,
        limit: int = 100,
    ) -> list[SalesDelivery]:
        pass

    @abstractmethod
    async def count_deliveries(
        self,
        company_id: str,
        status: SalesDeliveryStatus | None = None,
        sales_order_id: str | None = None,
    ) -> int:
        pass

    @abstractmethod
    async def update_delivery(
        self, delivery_id: str, delivery: SalesDelivery
    ) -> SalesDelivery | None:
        pass

    @abstractmethod
    async def get_next_delivery_number(self, company_id: str) -> str:
        pass

    # ---- Invoices ----
    @abstractmethod
    async def create_invoice(self, invoice: SalesInvoice) -> SalesInvoice:
        pass

    @abstractmethod
    async def get_invoice(self, invoice_id: str, company_id: str) -> SalesInvoice | None:
        pass

    @abstractmethod
    async def list_invoices(
        self,
        company_id: str,
        status: SalesInvoiceStatus | None = None,
        customer_id: str | None = None,
        skip: int = 0,
        limit: int = 100,
    ) -> list[SalesInvoice]:
        pass

    @abstractmethod
    async def count_invoices(
        self,
        company_id: str,
        status: SalesInvoiceStatus | None = None,
        customer_id: str | None = None,
    ) -> int:
        pass

    @abstractmethod
    async def update_invoice(self, invoice_id: str, invoice: SalesInvoice) -> SalesInvoice | None:
        pass

    @abstractmethod
    async def get_next_invoice_number(self, company_id: str) -> str:
        pass

    # ---- Payments ----
    @abstractmethod
    async def create_payment(self, payment: SalesPayment) -> SalesPayment:
        pass

    @abstractmethod
    async def get_payment(self, payment_id: str, company_id: str) -> SalesPayment | None:
        pass

    @abstractmethod
    async def list_payments(
        self,
        company_id: str,
        status: SalesPaymentStatus | None = None,
        customer_id: str | None = None,
        skip: int = 0,
        limit: int = 100,
    ) -> list[SalesPayment]:
        pass

    @abstractmethod
    async def count_payments(
        self,
        company_id: str,
        status: SalesPaymentStatus | None = None,
        customer_id: str | None = None,
    ) -> int:
        pass

    @abstractmethod
    async def update_payment(
        self, payment_id: str, payment: SalesPayment
    ) -> SalesPayment | None:
        pass

    @abstractmethod
    async def get_next_payment_number(self, company_id: str) -> str:
        pass
