"""
Expense models for managing purchases, maintenance, and other operational costs.
"""
import enum
from datetime import date, datetime
from sqlalchemy import Column, Integer, Float, String, Date, DateTime, Enum, ForeignKey, Text
from sqlalchemy.orm import relationship

from app.models.base import BaseModel


class ExpenseCategory(str, enum.Enum):
    """Expense category types."""
    PURCHASE = "purchase"           # Achats
    MAINTENANCE = "maintenance"     # Maintenance
    UPKEEP = "upkeep"              # Entretien
    SALARY = "salary"              # Salaires
    MARKETING = "marketing"        # Marketing
    UTILITIES = "utilities"        # Charges (eau, électricité, etc.)
    SUPPLIES = "supplies"          # Fournitures
    EQUIPMENT = "equipment"        # Équipements
    SERVICES = "services"          # Services externes
    OTHER = "other"                # Autres


class ExpenseStatus(str, enum.Enum):
    """Expense workflow status."""
    DRAFT = "draft"               # Brouillon
    SUBMITTED = "submitted"       # Soumis pour validation
    APPROVED = "approved"         # Approuvé
    REJECTED = "rejected"         # Rejeté
    PAID = "paid"                 # Payé


class Expense(BaseModel):
    """
    Expense record for tracking operational costs.

    Supports workflow validation: Draft -> Submitted -> Approved -> Paid
    Can have multiple file attachments.
    """
    __tablename__ = "expenses"

    # Basic info
    reference = Column(String(50), unique=True, nullable=False, index=True)
    description = Column(String(500), nullable=False)

    # Establishment and department
    establishment_id = Column(
        Integer,
        ForeignKey("establishments.id", ondelete="CASCADE"),
        nullable=False,
        index=True
    )
    department_code = Column(String(50), nullable=False, index=True)  # ACC, FB, SPA, ADM, etc.

    # Category and amounts
    category = Column(Enum(ExpenseCategory), nullable=False, index=True)
    amount_ht = Column(Float, nullable=False)
    tax_rate = Column(Float, default=18.0, nullable=False)
    tax_amount = Column(Float, nullable=False)
    amount_ttc = Column(Float, nullable=False)
    currency = Column(String(3), default="XOF", nullable=False)

    # Dates
    expense_date = Column(Date, nullable=False, index=True)
    due_date = Column(Date, nullable=True)
    paid_date = Column(Date, nullable=True)

    # Supplier info
    supplier_name = Column(String(200), nullable=True)
    supplier_reference = Column(String(100), nullable=True)

    # Workflow
    status = Column(Enum(ExpenseStatus), default=ExpenseStatus.DRAFT, nullable=False, index=True)
    submitted_at = Column(DateTime, nullable=True)
    submitted_by_id = Column(Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True)
    approved_at = Column(DateTime, nullable=True)
    approved_by_id = Column(Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True)
    rejection_reason = Column(Text, nullable=True)

    # Notes
    notes = Column(Text, nullable=True)

    # Relationships
    establishment = relationship("Establishment", backref="expenses")
    attachments = relationship(
        "ExpenseAttachment",
        back_populates="expense",
        cascade="all, delete-orphan"
    )
    submitted_by = relationship("User", foreign_keys=[submitted_by_id])
    approved_by = relationship("User", foreign_keys=[approved_by_id])

    def __repr__(self) -> str:
        return f"<Expense {self.reference}: {self.amount_ttc} {self.currency}>"

    @staticmethod
    def generate_reference(establishment_id: int, sequence: int) -> str:
        """Generate unique expense reference."""
        today = date.today()
        return f"DEP-{establishment_id:03d}-{today.year}{today.month:02d}-{sequence:04d}"


class ExpenseAttachment(BaseModel):
    """
    File attachment for expense documentation.

    Stores metadata about uploaded files (invoices, receipts, etc.)
    """
    __tablename__ = "expense_attachments"

    expense_id = Column(
        Integer,
        ForeignKey("expenses.id", ondelete="CASCADE"),
        nullable=False,
        index=True
    )
    file_name = Column(String(255), nullable=False)
    file_path = Column(String(500), nullable=False)
    file_size = Column(Integer, nullable=False)
    mime_type = Column(String(100), nullable=False)
    uploaded_by_id = Column(Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True)

    # Relationships
    expense = relationship("Expense", back_populates="attachments")
    uploaded_by = relationship("User")

    def __repr__(self) -> str:
        return f"<ExpenseAttachment {self.file_name}>"
