from datetime import date, datetime
from decimal import Decimal

from pydantic import BaseModel, Field

from app.domain.enums import (
    AmountType,
    GrnStatus,
    PaymentTerms,
    PreferredPaymentMethod,
    PurchaseOrderStatus,
    PurchasePaymentStatus,
    PurchaseType,
    VendorBillStatus,
    VendorBusinessType,
)


class Vendor(BaseModel):
    id: str | None = None
    company_id: str
    code: str
    name: str
    business_type: VendorBusinessType | None = None
    contact_person: str
    designation: str | None = None
    phone: str
    alternate_phone: str | None = None
    email: str | None = None
    website: str | None = None
    ntn: str | None = None
    sales_tax_no: str | None = None
    address_line1: str
    address_line2: str | None = None
    city: str
    state_province: str | None = None
    country: str = "Pakistan"
    postal_code: str | None = None
    notes: str | None = None
    payment_terms: PaymentTerms | None = None
    payment_terms_days: int = 30
    credit_limit: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    opening_balance: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    currency: str = "PKR"
    po_prefix: str | None = None
    default_warehouse_id: str | None = None
    default_warehouse_code: str | None = None
    default_warehouse_name: str | None = None
    preferred_payment_method: PreferredPaymentMethod | None = None
    logo: str | None = None
    address: str | None = None
    account_id: str | None = None
    is_active: bool = True
    created_at: datetime = Field(default_factory=datetime.utcnow)
    updated_at: datetime = Field(default_factory=datetime.utcnow)

    model_config = {"from_attributes": True}


class PurchaseOrderLine(BaseModel):
    id: str | None = None
    purchase_order_id: str | None = None
    line_number: int
    item_id: str
    item_sku: str | None = None
    item_name: str | None = None
    description: str | None = None
    base_unit_id: str | None = None
    base_unit_code: str | None = None
    base_unit_name: str | None = None
    quantity: Decimal = Field(..., decimal_places=4)
    received_quantity: Decimal = Field(default=Decimal("0.0000"), decimal_places=4)
    billed_quantity: Decimal = Field(default=Decimal("0.0000"), decimal_places=4)
    unit_price: Decimal = Field(..., decimal_places=4)
    discount_type: AmountType = AmountType.PERCENT
    discount_value: Decimal = Field(default=Decimal("0.0000"), decimal_places=4)
    discount_amount: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    tax_type: AmountType = AmountType.PERCENT
    tax_rate: Decimal = Field(default=Decimal("0.0000"), decimal_places=4)
    tax_amount: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    line_total: Decimal = Field(..., decimal_places=2)

    model_config = {"from_attributes": True}


class PurchaseOrder(BaseModel):
    id: str | None = None
    company_id: str
    po_number: str
    vendor_id: str
    vendor_code: str | None = None
    vendor_name: str | None = None
    vendor_email: str | None = None
    vendor_phone: str | None = None
    order_date: date
    expected_date: date | None = None
    delivery_date: date | None = None
    payment_terms: PaymentTerms | None = None
    currency: str = "PKR"
    warehouse_id: str | None = None
    warehouse_code: str | None = None
    warehouse_name: str | None = None
    ship_to: str | None = None
    purchase_type: PurchaseType | None = None
    reference_number: str | None = None
    department: str | None = None
    notes: str | None = None
    terms_and_conditions: str | None = None
    attachments: list[str] = Field(default_factory=list)
    status: PurchaseOrderStatus = PurchaseOrderStatus.PENDING
    subtotal: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    discount_amount: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    tax_amount: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    total_amount: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    created_by: str | None = None
    approved_at: datetime | None = None
    cancelled_at: datetime | None = None
    lines: list[PurchaseOrderLine] = Field(default_factory=list)
    created_at: datetime = Field(default_factory=datetime.utcnow)
    updated_at: datetime = Field(default_factory=datetime.utcnow)

    model_config = {"from_attributes": True}


class GoodsReceiptLine(BaseModel):
    id: str | None = None
    goods_receipt_id: str | None = None
    purchase_order_line_id: str
    line_number: int
    item_id: str
    quantity_ordered: Decimal = Field(..., decimal_places=4)
    quantity_received: Decimal = Field(..., decimal_places=4)
    unit_cost: Decimal = Field(..., decimal_places=4)
    notes: str | None = None

    model_config = {"from_attributes": True}


class GoodsReceipt(BaseModel):
    id: str | None = None
    company_id: str
    grn_number: str
    purchase_order_id: str
    vendor_id: str
    receipt_date: date
    status: GrnStatus = GrnStatus.DRAFT
    notes: str | None = None
    confirmed_at: datetime | None = None
    lines: list[GoodsReceiptLine] = Field(default_factory=list)
    created_at: datetime = Field(default_factory=datetime.utcnow)
    updated_at: datetime = Field(default_factory=datetime.utcnow)

    model_config = {"from_attributes": True}


class VendorBillLine(BaseModel):
    id: str | None = None
    vendor_bill_id: str | None = None
    line_number: int
    item_id: str | None = None
    account_id: str | None = None
    description: str | None = None
    quantity: Decimal = Field(default=Decimal("1.0000"), decimal_places=4)
    unit_price: Decimal = Field(..., decimal_places=4)
    tax_rate: Decimal = Field(default=Decimal("0.0000"), decimal_places=4)
    line_total: Decimal = Field(..., decimal_places=2)
    purchase_order_line_id: str | None = None
    goods_receipt_line_id: str | None = None

    model_config = {"from_attributes": True}


class VendorBill(BaseModel):
    id: str | None = None
    company_id: str
    bill_number: str
    vendor_invoice_number: str | None = None
    vendor_id: str
    purchase_order_id: str | None = None
    goods_receipt_id: str | None = None
    bill_date: date
    due_date: date | None = None
    status: VendorBillStatus = VendorBillStatus.DRAFT
    ap_account_id: str | None = None
    notes: str | None = None
    subtotal: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    tax_amount: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    total_amount: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    amount_paid: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    voucher_id: str | None = None
    posted_at: datetime | None = None
    lines: list[VendorBillLine] = Field(default_factory=list)
    created_at: datetime = Field(default_factory=datetime.utcnow)
    updated_at: datetime = Field(default_factory=datetime.utcnow)

    model_config = {"from_attributes": True}


class PurchasePaymentAllocation(BaseModel):
    id: str | None = None
    purchase_payment_id: str | None = None
    vendor_bill_id: str
    amount: Decimal = Field(..., decimal_places=2)

    model_config = {"from_attributes": True}


class PurchasePayment(BaseModel):
    id: str | None = None
    company_id: str
    payment_number: str
    vendor_id: str
    payment_date: date
    status: PurchasePaymentStatus = PurchasePaymentStatus.DRAFT
    payment_method: str = "bank"
    bank_account_id: str | None = None
    ap_account_id: str | None = None
    reference: str | None = None
    notes: str | None = None
    total_amount: Decimal = Field(default=Decimal("0.00"), decimal_places=2)
    voucher_id: str | None = None
    posted_at: datetime | None = None
    allocations: list[PurchasePaymentAllocation] = Field(default_factory=list)
    created_at: datetime = Field(default_factory=datetime.utcnow)
    updated_at: datetime = Field(default_factory=datetime.utcnow)

    model_config = {"from_attributes": True}
