from datetime import date, datetime
from decimal import Decimal

from pydantic import BaseModel, Field

from app.domain.enums import (
    CustomerBusinessType,
    PaymentTerms,
    PreferredPaymentMethod,
    SalesDeliveryStatus,
    SalesInvoiceStatus,
    SalesOrderStatus,
    SalesPaymentStatus,
)


class CustomerCreate(BaseModel):
    code: str | None = Field(
        None,
        min_length=1,
        max_length=30,
        description="Customer code; auto-generated (e.g. CUS-00001) if omitted",
    )
    name: str = Field(..., min_length=1, max_length=200, description="Customer name")
    business_type: CustomerBusinessType | 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)
    so_prefix: str | None = Field(None, max_length=30, description="Sales order prefix")
    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 = Field(
        None, description="Optional AR account; auto-created under 1140 if omitted"
    )
    is_active: bool = True


class CustomerUpdate(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: CustomerBusinessType | 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)
    so_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 CustomerResponse(BaseModel):
    id: str
    company_id: str
    code: str
    name: str
    business_type: CustomerBusinessType | 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
    so_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}


# ---- Sales orders ----
class SalesOrderLineCreate(BaseModel):
    item_id: str
    description: str | None = None
    quantity: Decimal = Field(..., gt=0)
    unit_price: Decimal = Field(..., ge=0)
    tax_rate: Decimal = Field(default=Decimal("0.0000"), ge=0)


class SalesOrderCreate(BaseModel):
    customer_id: str
    warehouse_id: str | None = None
    order_date: date
    delivery_date: date | None = None
    delivery_address: str | None = Field(None, max_length=500)
    delivery_contact: str | None = Field(None, max_length=200)
    delivery_phone: str | None = Field(None, max_length=50)
    payment_terms: PaymentTerms | None = None
    currency: str = Field(default="PKR", max_length=10)
    notes: str | None = None
    lines: list[SalesOrderLineCreate] = Field(..., min_length=1)


class SalesOrderUpdate(BaseModel):
    customer_id: str | None = None
    warehouse_id: str | None = None
    order_date: date | None = None
    delivery_date: date | None = None
    delivery_address: str | None = Field(None, max_length=500)
    delivery_contact: str | None = Field(None, max_length=200)
    delivery_phone: str | None = Field(None, max_length=50)
    payment_terms: PaymentTerms | None = None
    currency: str | None = Field(None, max_length=10)
    notes: str | None = None
    lines: list[SalesOrderLineCreate] | None = None


class SalesOrderLineResponse(BaseModel):
    id: str | None = None
    sales_order_id: str | None = None
    line_number: int
    item_id: str
    item_sku: str | None = None
    item_name: str | None = None
    description: str | None
    quantity: Decimal
    reserved_quantity: Decimal
    picked_quantity: Decimal
    shipped_quantity: Decimal
    invoiced_quantity: Decimal
    available_quantity: Decimal
    is_available: bool
    unit_price: Decimal
    tax_rate: Decimal
    tax_amount: Decimal
    line_total: Decimal

    model_config = {"from_attributes": True}


class SalesOrderResponse(BaseModel):
    id: str
    company_id: str
    so_number: str
    customer_id: str
    customer_code: str | None = None
    customer_name: str | None = None
    customer_email: str | None = None
    customer_phone: str | None = None
    warehouse_id: str | None = None
    warehouse_code: str | None = None
    warehouse_name: str | None = None
    order_date: date
    delivery_date: date | None = None
    delivery_address: str | None = None
    delivery_contact: str | None = None
    delivery_phone: str | None = None
    payment_terms: PaymentTerms | None = None
    currency: str
    notes: str | None
    status: SalesOrderStatus
    subtotal: Decimal
    tax_amount: Decimal
    total_amount: Decimal
    created_by: str | None
    confirmed_at: datetime | None
    cancelled_at: datetime | None
    lines: list[SalesOrderLineResponse]
    created_at: datetime
    updated_at: datetime

    model_config = {"from_attributes": True}


class AvailabilityLineSummary(BaseModel):
    sales_order_line_id: str | None = None
    item_id: str
    item_sku: str | None = None
    item_name: str | None = None
    quantity_ordered: Decimal
    quantity_on_hand: Decimal
    quantity_reserved: Decimal
    quantity_available: Decimal
    is_available: bool


class AvailabilityCheckResponse(BaseModel):
    order: SalesOrderResponse
    all_available: bool
    lines: list[AvailabilityLineSummary]


class SalesOrderPickLine(BaseModel):
    sales_order_line_id: str
    quantity: Decimal = Field(..., gt=0)


class SalesOrderPickRequest(BaseModel):
    lines: list[SalesOrderPickLine] | None = None


# ---- Deliveries ----
class SalesDeliveryLineCreate(BaseModel):
    sales_order_line_id: str
    quantity: Decimal = Field(..., gt=0)
    notes: str | None = None


class SalesDeliveryCreate(BaseModel):
    sales_order_id: str
    delivery_date: date
    notes: str | None = None
    lines: list[SalesDeliveryLineCreate] = Field(..., min_length=1)


class SalesDeliveryLineResponse(BaseModel):
    id: str | None = None
    sales_delivery_id: str | None = None
    sales_order_line_id: str
    line_number: int
    item_id: str
    quantity: Decimal
    notes: str | None

    model_config = {"from_attributes": True}


class SalesDeliveryResponse(BaseModel):
    id: str
    company_id: str
    delivery_number: str
    sales_order_id: str
    customer_id: str
    delivery_date: date
    status: SalesDeliveryStatus
    notes: str | None
    confirmed_at: datetime | None
    lines: list[SalesDeliveryLineResponse]
    created_at: datetime
    updated_at: datetime

    model_config = {"from_attributes": True}


# ---- Invoices ----
class SalesInvoiceLineCreate(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
    sales_order_line_id: str | None = None
    sales_delivery_line_id: str | None = None


class SalesInvoiceCreate(BaseModel):
    customer_id: str
    invoice_date: date
    due_date: date | None = None
    sales_order_id: str | None = None
    delivery_id: str | None = None
    ar_account_id: str | None = None
    notes: str | None = None
    lines: list[SalesInvoiceLineCreate] = Field(..., min_length=1)


class SalesInvoiceLineResponse(BaseModel):
    id: str | None = None
    sales_invoice_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
    sales_order_line_id: str | None
    sales_delivery_line_id: str | None

    model_config = {"from_attributes": True}


class SalesInvoiceResponse(BaseModel):
    id: str
    company_id: str
    invoice_number: str
    customer_id: str
    sales_order_id: str | None
    delivery_id: str | None
    invoice_date: date
    due_date: date | None
    status: SalesInvoiceStatus
    ar_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[SalesInvoiceLineResponse]
    created_at: datetime
    updated_at: datetime

    model_config = {"from_attributes": True}


# ---- Payments ----
class SalesPaymentAllocationCreate(BaseModel):
    sales_invoice_id: str
    amount: Decimal = Field(..., gt=0)


class SalesPaymentCreate(BaseModel):
    customer_id: str
    payment_date: date
    payment_method: str = Field(default="bank", max_length=30)
    bank_account_id: str | None = None
    ar_account_id: str | None = None
    reference: str | None = None
    notes: str | None = None
    allocations: list[SalesPaymentAllocationCreate] = Field(..., min_length=1)


class SalesPaymentAllocationResponse(BaseModel):
    id: str | None = None
    sales_payment_id: str | None = None
    sales_invoice_id: str
    amount: Decimal

    model_config = {"from_attributes": True}


class SalesPaymentResponse(BaseModel):
    id: str
    company_id: str
    payment_number: str
    customer_id: str
    payment_date: date
    status: SalesPaymentStatus
    payment_method: str
    bank_account_id: str | None
    ar_account_id: str | None
    reference: str | None
    notes: str | None
    total_amount: Decimal
    voucher_id: str | None
    posted_at: datetime | None
    allocations: list[SalesPaymentAllocationResponse]
    created_at: datetime
    updated_at: datetime

    model_config = {"from_attributes": True}
