"""
Budget models for financial planning and variance analysis.
"""
import enum
from datetime import date
from sqlalchemy import Column, Integer, Float, String, Date, Enum, ForeignKey, Text, Boolean
from sqlalchemy.orm import relationship

from app.models.base import BaseModel


class BudgetPeriod(str, enum.Enum):
    """Budget period types."""
    MONTHLY = "monthly"
    QUARTERLY = "quarterly"
    YEARLY = "yearly"


class BudgetStatus(str, enum.Enum):
    """Budget status."""
    DRAFT = "draft"
    APPROVED = "approved"
    LOCKED = "locked"


class Budget(BaseModel):
    """
    Budget definition for a specific period and establishment.

    A budget contains financial targets for revenue and expenses
    by department for a given period.
    """
    __tablename__ = "budgets"

    # Basic info
    name = Column(String(200), nullable=False)
    establishment_id = Column(Integer, ForeignKey("establishments.id", ondelete="CASCADE"), nullable=False, index=True)

    # Period
    period_type = Column(Enum(BudgetPeriod), nullable=False, index=True)
    year = Column(Integer, nullable=False, index=True)
    month = Column(Integer, nullable=True, index=True)  # For monthly budgets (1-12)
    quarter = Column(Integer, nullable=True, index=True)  # For quarterly budgets (1-4)

    # Dates
    start_date = Column(Date, nullable=False)
    end_date = Column(Date, nullable=False)

    # Status
    status = Column(Enum(BudgetStatus), default=BudgetStatus.DRAFT, nullable=False, index=True)

    # Metadata
    notes = Column(Text, nullable=True)
    created_by_id = Column(Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True)
    approved_by_id = Column(Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True)
    approved_at = Column(Date, nullable=True)

    # Relationships
    establishment = relationship("Establishment", back_populates="budgets")
    lines = relationship("BudgetLine", back_populates="budget", cascade="all, delete-orphan")
    created_by = relationship("User", foreign_keys=[created_by_id])
    approved_by = relationship("User", foreign_keys=[approved_by_id])

    @property
    def total_revenue(self) -> float:
        """Calculate total budgeted revenue."""
        return sum(line.amount for line in self.lines if line.line_type == BudgetLineType.REVENUE)

    @property
    def total_expenses(self) -> float:
        """Calculate total budgeted expenses."""
        return sum(line.amount for line in self.lines if line.line_type == BudgetLineType.EXPENSE)

    @property
    def net_income(self) -> float:
        """Calculate budgeted net income (revenue - expenses)."""
        return self.total_revenue - self.total_expenses

    def __repr__(self) -> str:
        return f"<Budget {self.name} ({self.year})>"


class BudgetLineType(str, enum.Enum):
    """Budget line type."""
    REVENUE = "revenue"
    EXPENSE = "expense"


class BudgetLine(BaseModel):
    """
    Individual budget line item.

    Represents a specific revenue or expense target for a department.
    """
    __tablename__ = "budget_lines"

    budget_id = Column(Integer, ForeignKey("budgets.id", ondelete="CASCADE"), nullable=False, index=True)

    # Type and categorization
    line_type = Column(Enum(BudgetLineType), nullable=False, index=True)
    department_code = Column(String(50), nullable=False, index=True)
    category = Column(String(100), nullable=True)  # e.g., "Room Revenue", "Salaries", "Utilities"

    # Amount
    amount = Column(Float, nullable=False)
    currency = Column(String(3), default="XOF", nullable=False)

    # Description
    description = Column(Text, nullable=True)
    notes = Column(Text, nullable=True)

    # Relationships
    budget = relationship("Budget", back_populates="lines")

    def __repr__(self) -> str:
        return f"<BudgetLine {self.department_code}: {self.amount}>"


class VarianceAnalysis(BaseModel):
    """
    Variance analysis comparing actual vs budget.

    This is a cached/computed table for performance.
    Can be regenerated from actual data and budgets.
    """
    __tablename__ = "variance_analyses"

    establishment_id = Column(Integer, ForeignKey("establishments.id", ondelete="CASCADE"), nullable=False, index=True)
    budget_id = Column(Integer, ForeignKey("budgets.id", ondelete="CASCADE"), nullable=False, index=True)

    # Period
    analysis_date = Column(Date, nullable=False, index=True)
    period_type = Column(Enum(BudgetPeriod), nullable=False)

    # Department
    department_code = Column(String(50), nullable=False, index=True)

    # Amounts
    budget_amount = Column(Float, nullable=False)
    actual_amount = Column(Float, nullable=False)
    variance_amount = Column(Float, nullable=False)  # Actual - Budget
    variance_percent = Column(Float, nullable=False)  # (Actual - Budget) / Budget * 100

    # Comparisons
    prior_year_amount = Column(Float, nullable=True)  # N-1 amount
    yoy_variance = Column(Float, nullable=True)  # Year-over-year variance
    yoy_variance_percent = Column(Float, nullable=True)

    # Flags
    is_favorable = Column(Boolean, nullable=False)  # True if variance is favorable

    # Relationships
    establishment = relationship("Establishment")
    budget = relationship("Budget")

    def __repr__(self) -> str:
        return f"<VarianceAnalysis {self.department_code} {self.analysis_date}>"
