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 VendorCreate(BaseModel):
    code: str | None = Field(
        None,
        min_length=1,
        max_length=30,
        description="Vendor code; auto-generated (e.g. VEN-00001) if omitted",
    )
    name: str = Field(..., min_length=1, max_length=200, description="Vendor / Supplier name")
    business_type: VendorBusinessType | None = None
    contact_person: str = Field(..., min_length=1, max_length=200)
    designation: str | None = Field(None, max_length=100)
    phone: str = Field(..., min_length=1, max_length=50)
    alternate_phone: str | None = Field(None, max_length=50)
    email: str | None = Field(None, max_length=255)
    website: str | None = Field(None, max_length=255)
    ntn: str | None = Field(None, max_length=50)
    sales_tax_no: str | None = Field(None, max_length=50)
    address_line1: str = Field(..., min_length=1, max_length=255)
    address_line2: str | None = Field(None, max_length=255)
    city: str = Field(..., min_length=1, max_length=100)
    state_province: str | None = Field(None, max_length=100)
    country: str = Field(default="Pakistan", min_length=1, max_length=100)
    postal_code: str | None = Field(None, max_length=30)
    notes: str | None = Field(None, max_length=500)
    payment_terms: PaymentTerms | None = None
    payment_terms_days: int = Field(default=30, ge=0)
    credit_limit: Decimal = Field(default=Decimal("0.00"), ge=0)
    opening_balance: Decimal = Field(default=Decimal("0.00"))
    currency: str = Field(default="PKR", max_length=10)
    po_prefix: str | None = Field(None, max_length=30)
    default_warehouse_id: str | None = None
    preferred_payment_method: PreferredPaymentMethod | None = None
    logo: str | None = Field(
        None, max_length=500, description="Logo path if already uploaded; prefer multipart file"
    )
    account_id: str | None = None
    is_active: bool = True


class VendorUpdate(BaseModel):
    code: str | None = Field(None, min_length=1, max_length=30)
    name: str | None = Field(None, min_length=1, max_length=200)
    business_type: VendorBusinessType | None = None
    contact_person: str | None = Field(None, min_length=1, max_length=200)
    designation: str | None = Field(None, max_length=100)
    phone: str | None = Field(None, min_length=1, max_length=50)
    alternate_phone: str | None = Field(None, max_length=50)
    email: str | None = Field(None, max_length=255)
    website: str | None = Field(None, max_length=255)
    ntn: str | None = Field(None, max_length=50)
    sales_tax_no: str | None = Field(None, max_length=50)
    address_line1: str | None = Field(None, min_length=1, max_length=255)
    address_line2: str | None = Field(None, max_length=255)
    city: str | None = Field(None, min_length=1, max_length=100)
    state_province: str | None = Field(None, max_length=100)
    country: str | None = Field(None, min_length=1, max_length=100)
    postal_code: str | None = Field(None, max_length=30)
    notes: str | None = Field(None, max_length=500)
    payment_terms: PaymentTerms | None = None
    payment_terms_days: int | None = Field(None, ge=0)
    credit_limit: Decimal | None = Field(None, ge=0)
    opening_balance: Decimal | None = None
    currency: str | None = Field(None, max_length=10)
    po_prefix: str | None = Field(None, max_length=30)
    default_warehouse_id: str | None = None
    preferred_payment_method: PreferredPaymentMethod | None = None
    logo: str | None = Field(None, max_length=500)
    account_id: str | None = None
    is_active: bool | None = None


class VendorResponse(BaseModel):
    id: str
    company_id: str
    code: str
    name: str
    business_type: VendorBusinessType | None
    contact_person: str
    designation: str | None
    phone: str
    alternate_phone: str | None
    email: str | None
    website: str | None
    ntn: str | None
    sales_tax_no: str | None
    address_line1: str
    address_line2: str | None
    city: str
    state_province: str | None
    country: str
    postal_code: str | None
    notes: str | None
    payment_terms: PaymentTerms | None
    payment_terms_days: int
    credit_limit: Decimal
    opening_balance: Decimal
    currency: str
    po_prefix: str | None
    default_warehouse_id: str | None
    default_warehouse_code: str | None = None
    default_warehouse_name: str | None = None
    preferred_payment_method: PreferredPaymentMethod | None
    logo: str | None
    address: str | None
    account_id: str | None
    is_active: bool
    created_at: datetime
    updated_at: datetime

    model_config = {"from_attributes": True}


class PurchaseOrderLineCreate(BaseModel):
    item_id: str
    description: str | None = None
    base_unit_id: str | None = None
    quantity: Decimal = Field(..., gt=0)
    unit_price: Decimal = Field(..., ge=0)
    discount_type: AmountType = AmountType.PERCENT
    discount_value: Decimal = Field(default=Decimal("0.0000"), ge=0)
    tax_type: AmountType = AmountType.PERCENT
    tax_rate: Decimal = Field(default=Decimal("0.0000"), ge=0, description="Tax % or fixed amount")


class PurchaseOrderCreate(BaseModel):
    vendor_id: str
    order_date: date
    expected_date: date | None = Field(None, description="Required date")
    delivery_date: date | None = None
    payment_terms: PaymentTerms | None = None
    currency: str = Field(default="PKR", max_length=10)
    warehouse_id: str | None = None
    ship_to: str | None = Field(None, max_length=255)
    purchase_type: PurchaseType | None = None
    reference_number: str | None = Field(None, max_length=100)
    department: str | None = Field(None, max_length=100)
    notes: str | None = None
    terms_and_conditions: str | None = None
    attachments: list[str] = Field(default_factory=list)
    lines: list[PurchaseOrderLineCreate] = Field(..., min_length=1)


class PurchaseOrderUpdate(BaseModel):
    vendor_id: str | None = None
    order_date: date | None = None
    expected_date: date | None = None
    delivery_date: date | None = None
    payment_terms: PaymentTerms | None = None
    currency: str | None = Field(None, max_length=10)
    warehouse_id: str | None = None
    ship_to: str | None = Field(None, max_length=255)
    purchase_type: PurchaseType | None = None
    reference_number: str | None = Field(None, max_length=100)
    department: str | None = Field(None, max_length=100)
    notes: str | None = None
    terms_and_conditions: str | None = None
    attachments: list[str] | None = None
    lines: list[PurchaseOrderLineCreate] | None = None


class PurchaseOrderLineResponse(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
    base_unit_id: str | None = None
    base_unit_code: str | None = None
    base_unit_name: str | None = None
    quantity: Decimal
    received_quantity: Decimal
    billed_quantity: Decimal
    unit_price: Decimal
    discount_type: AmountType
    discount_value: Decimal
    discount_amount: Decimal
    tax_type: AmountType
    tax_rate: Decimal
    tax_amount: Decimal
    line_total: Decimal

    model_config = {"from_attributes": True}


class PurchaseOrderResponse(BaseModel):
    id: str
    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
    delivery_date: date | None = None
    payment_terms: PaymentTerms | None = None
    currency: str
    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
    terms_and_conditions: str | None = None
    attachments: list[str] = Field(default_factory=list)
    status: PurchaseOrderStatus
    subtotal: Decimal
    discount_amount: Decimal = Decimal("0.00")
    tax_amount: Decimal
    total_amount: Decimal
    created_by: str | None
    approved_at: datetime | None
    cancelled_at: datetime | None
    lines: list[PurchaseOrderLineResponse]
    created_at: datetime
    updated_at: datetime

    model_config = {"from_attributes": True}


class GoodsReceiptLineCreate(BaseModel):
    purchase_order_line_id: str
    quantity_received: Decimal = Field(..., gt=0)
    unit_cost: Decimal | None = Field(None, ge=0)
    notes: str | None = None


class GoodsReceiptCreate(BaseModel):
    purchase_order_id: str
    receipt_date: date
    notes: str | None = None
    lines: list[GoodsReceiptLineCreate] = Field(..., min_length=1)


class GoodsReceiptLineResponse(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
    quantity_received: Decimal
    unit_cost: Decimal
    notes: str | None

    model_config = {"from_attributes": True}


class GoodsReceiptResponse(BaseModel):
    id: str
    company_id: str
    grn_number: str
    purchase_order_id: str
    vendor_id: str
    receipt_date: date
    status: GrnStatus
    notes: str | None
    confirmed_at: datetime | None
    lines: list[GoodsReceiptLineResponse]
    created_at: datetime
    updated_at: datetime

    model_config = {"from_attributes": True}


class VendorBillLineCreate(BaseModel):
    item_id: str | None = None
    account_id: str | None = None
    description: str | None = None
    quantity: Decimal = Field(default=Decimal("1.0000"), gt=0)
    unit_price: Decimal = Field(..., ge=0)
    tax_rate: Decimal = Field(default=Decimal("0.0000"), ge=0)
    line_total: Decimal | None = None
    purchase_order_line_id: str | None = None
    goods_receipt_line_id: str | None = None


class VendorBillCreate(BaseModel):
    vendor_id: str
    bill_date: date
    due_date: date | None = None
    vendor_invoice_number: str | None = None
    purchase_order_id: str | None = None
    goods_receipt_id: str | None = None
    ap_account_id: str | None = None
    notes: str | None = None
    lines: list[VendorBillLineCreate] = Field(..., min_length=1)


class VendorBillLineResponse(BaseModel):
    id: str | None = None
    vendor_bill_id: str | None = None
    line_number: int
    item_id: str | None
    account_id: str | None
    description: str | None
    quantity: Decimal
    unit_price: Decimal
    tax_rate: Decimal
    line_total: Decimal
    purchase_order_line_id: str | None
    goods_receipt_line_id: str | None

    model_config = {"from_attributes": True}


class VendorBillResponse(BaseModel):
    id: str
    company_id: str
    bill_number: str
    vendor_invoice_number: str | None
    vendor_id: str
    purchase_order_id: str | None
    goods_receipt_id: str | None
    bill_date: date
    due_date: date | None
    status: VendorBillStatus
    ap_account_id: str | None
    notes: str | None
    subtotal: Decimal
    tax_amount: Decimal
    total_amount: Decimal
    amount_paid: Decimal
    voucher_id: str | None
    posted_at: datetime | None
    lines: list[VendorBillLineResponse]
    created_at: datetime
    updated_at: datetime

    model_config = {"from_attributes": True}


class PurchasePaymentAllocationCreate(BaseModel):
    vendor_bill_id: str
    amount: Decimal = Field(..., gt=0)


class PurchasePaymentCreate(BaseModel):
    vendor_id: str
    payment_date: date
    payment_method: str = Field(default="bank", max_length=30)
    bank_account_id: str | None = None
    ap_account_id: str | None = None
    reference: str | None = None
    notes: str | None = None
    allocations: list[PurchasePaymentAllocationCreate] = Field(..., min_length=1)


class PurchasePaymentAllocationResponse(BaseModel):
    id: str | None = None
    purchase_payment_id: str | None = None
    vendor_bill_id: str
    amount: Decimal

    model_config = {"from_attributes": True}


class PurchasePaymentResponse(BaseModel):
    id: str
    company_id: str
    payment_number: str
    vendor_id: str
    payment_date: date
    status: PurchasePaymentStatus
    payment_method: str
    bank_account_id: str | None
    ap_account_id: str | None
    reference: str | None
    notes: str | None
    total_amount: Decimal
    voucher_id: str | None
    posted_at: datetime | None
    allocations: list[PurchasePaymentAllocationResponse]
    created_at: datetime
    updated_at: datetime

    model_config = {"from_attributes": True}
