"""Expenses models."""

from __future__ import annotations

import enum
from datetime import date, datetime
from decimal import Decimal
from typing import TYPE_CHECKING

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

from app.models.base import Base

if TYPE_CHECKING:
    from app.models.user import User


class StatusExpense(str, enum.Enum):
    DRAFT = "draft"
    SUBMITTED = "submitted"
    APPROVED = "approved"
    REJECTED = "rejected"


class ExpenseKategori(Base):
    __tablename__ = "expense_kategori"

    id: Mapped[int] = mapped_column(primary_key=True)
    spbu_id: Mapped[int | None] = mapped_column(
        ForeignKey("master_spbu.id", ondelete="CASCADE"), nullable=True, index=True
    )
    nama: Mapped[str] = mapped_column(String(100), nullable=False)
    urutan: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    is_active: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)

    expenses: Mapped[list["Expense"]] = relationship(back_populates="kategori")


class Expense(Base):
    __tablename__ = "expenses"

    id: Mapped[int] = mapped_column(primary_key=True)
    spbu_id: Mapped[int] = mapped_column(
        ForeignKey("master_spbu.id", ondelete="CASCADE"), nullable=False, index=True
    )
    laporan_shift_id: Mapped[int | None] = mapped_column(
        ForeignKey("laporan_shift.id", ondelete="CASCADE"), nullable=True, index=True
    )
    tanggal: Mapped[date] = mapped_column(Date, nullable=False)
    kategori_id: Mapped[int] = mapped_column(
        ForeignKey("expense_kategori.id", ondelete="RESTRICT"), nullable=False
    )
    keterangan: Mapped[str | None] = mapped_column(Text, nullable=True)
    jumlah: Mapped[Decimal] = mapped_column(Numeric(15, 2), nullable=False)
    bukti_url: Mapped[str | None] = mapped_column(String(500), nullable=True)
    status: Mapped[str] = mapped_column(String(20), nullable=False, default=StatusExpense.DRAFT)
    submitted_by_id: Mapped[int | None] = mapped_column(ForeignKey("master_user.id", ondelete="SET NULL"), nullable=True)
    submitted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
    reviewed_by_id: Mapped[int | None] = mapped_column(ForeignKey("master_user.id", ondelete="SET NULL"), nullable=True)
    reviewed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
    catatan_review: Mapped[str | None] = mapped_column(Text, nullable=True)
    recalled_by_id: Mapped[int | None] = mapped_column(ForeignKey("master_user.id", ondelete="SET NULL"), nullable=True)
    recalled_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
    unlocked_by_id: Mapped[int | None] = mapped_column(ForeignKey("master_user.id", ondelete="SET NULL"), nullable=True)
    unlocked_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
    unlock_reason: Mapped[str | None] = mapped_column(Text, nullable=True)
    created_by_id: Mapped[int | None] = mapped_column(
        ForeignKey("master_user.id", ondelete="SET NULL"), nullable=True
    )
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now(), nullable=False
    )

    kategori: Mapped["ExpenseKategori"] = relationship(back_populates="expenses")
    created_by: Mapped["User | None"] = relationship(foreign_keys=[created_by_id])
    submitted_by: Mapped["User | None"] = relationship(foreign_keys=[submitted_by_id])
    reviewed_by: Mapped["User | None"] = relationship(foreign_keys=[reviewed_by_id])
    recalled_by: Mapped["User | None"] = relationship(foreign_keys=[recalled_by_id])
    unlocked_by: Mapped["User | None"] = relationship(foreign_keys=[unlocked_by_id])
