from __future__ import annotations

import uuid
from datetime import date, datetime
from decimal import Decimal
from typing import Any

from sqlalchemy import Date, DateTime, ForeignKey, Integer, Numeric, String, Text, func
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.types import JSON

from app.db.base_class import Base


class ExpenseClaim(Base):
    __tablename__ = "expense_claims"

    id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    claim_no: Mapped[str] = mapped_column(String(50), unique=True, index=True)
    employee_id: Mapped[str | None] = mapped_column(
        ForeignKey("employees.id"), nullable=True, index=True
    )
    employee_name: Mapped[str] = mapped_column(String(100), index=True)
    department_id: Mapped[str | None] = mapped_column(
        ForeignKey("organization_units.id"), nullable=True, index=True
    )
    department_name: Mapped[str] = mapped_column(String(100), index=True)
    project_code: Mapped[str | None] = mapped_column(String(50), nullable=True)
    expense_type: Mapped[str] = mapped_column(String(50), index=True)
    reason: Mapped[str] = mapped_column(Text())
    location: Mapped[str] = mapped_column(String(100))
    amount: Mapped[Decimal] = mapped_column(Numeric(12, 2))
    currency: Mapped[str] = mapped_column(String(10), default="CNY")
    invoice_count: Mapped[int] = mapped_column(Integer, default=0)
    occurred_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), index=True)
    submitted_at: Mapped[datetime | None] = mapped_column(
        DateTime(timezone=True), nullable=True, index=True
    )
    status: Mapped[str] = mapped_column(String(30), index=True)
    approval_stage: Mapped[str | None] = mapped_column(String(50), nullable=True)
    risk_flags_json: Mapped[list[Any]] = mapped_column(JSON, default=list)
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
    )

    items = relationship(
        "ExpenseClaimItem",
        back_populates="claim",
        cascade="all, delete-orphan",
        order_by="asc(ExpenseClaimItem.item_date)",
    )


class ExpenseClaimItem(Base):
    __tablename__ = "expense_claim_items"

    id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    claim_id: Mapped[str] = mapped_column(ForeignKey("expense_claims.id"), index=True)
    item_date: Mapped[date] = mapped_column(Date(), index=True)
    item_type: Mapped[str] = mapped_column(String(50))
    item_reason: Mapped[str] = mapped_column(Text())
    item_location: Mapped[str] = mapped_column(String(100))
    item_amount: Mapped[Decimal] = mapped_column(Numeric(12, 2))
    invoice_id: Mapped[str | None] = mapped_column(String(100), nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
    )

    claim = relationship("ExpenseClaim", back_populates="items")


class AccountsReceivableRecord(Base):
    __tablename__ = "accounts_receivable"

    id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    receivable_no: Mapped[str] = mapped_column(String(50), unique=True, index=True)
    customer_id: Mapped[str] = mapped_column(String(64), index=True)
    customer_name: Mapped[str] = mapped_column(String(120), index=True)
    contract_no: Mapped[str | None] = mapped_column(String(100), nullable=True)
    invoice_no: Mapped[str | None] = mapped_column(String(100), nullable=True)
    amount_receivable: Mapped[Decimal] = mapped_column(Numeric(12, 2))
    amount_received: Mapped[Decimal] = mapped_column(Numeric(12, 2))
    amount_outstanding: Mapped[Decimal] = mapped_column(Numeric(12, 2))
    currency: Mapped[str] = mapped_column(String(10), default="CNY")
    posting_date: Mapped[date] = mapped_column(Date(), index=True)
    due_date: Mapped[date] = mapped_column(Date(), index=True)
    aging_days: Mapped[int] = mapped_column(Integer, default=0)
    status: Mapped[str] = mapped_column(String(30), index=True)
    risk_flags_json: Mapped[list[Any]] = mapped_column(JSON, default=list)
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
    )


class AccountsPayableRecord(Base):
    __tablename__ = "accounts_payable"

    id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    payable_no: Mapped[str] = mapped_column(String(50), unique=True, index=True)
    vendor_id: Mapped[str] = mapped_column(String(64), index=True)
    vendor_name: Mapped[str] = mapped_column(String(120), index=True)
    invoice_no: Mapped[str | None] = mapped_column(String(100), nullable=True)
    amount_payable: Mapped[Decimal] = mapped_column(Numeric(12, 2))
    amount_paid: Mapped[Decimal] = mapped_column(Numeric(12, 2))
    amount_outstanding: Mapped[Decimal] = mapped_column(Numeric(12, 2))
    currency: Mapped[str] = mapped_column(String(10), default="CNY")
    posting_date: Mapped[date] = mapped_column(Date(), index=True)
    due_date: Mapped[date] = mapped_column(Date(), index=True)
    aging_days: Mapped[int] = mapped_column(Integer, default=0)
    status: Mapped[str] = mapped_column(String(30), index=True)
    risk_flags_json: Mapped[list[Any]] = mapped_column(JSON, default=list)
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
    )
