"""PB (Permintaan Barang) models."""

from __future__ import annotations

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

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

from app.models.base import Base, TimestampMixin

if TYPE_CHECKING:
    from app.models.user import User
    from app.models.spbu import Spbu
    from app.models.expenses import Expense


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


class StatusPBItem(str, enum.Enum):
    PENDING = "pending"
    APPROVED = "approved"
    REJECTED = "rejected"


class Project(Base, TimestampMixin):
    __tablename__ = "pb_project"

    __table_args__ = (
        Index("ix_pb_project_spbu_id", "spbu_id"),
    )

    id: Mapped[int] = mapped_column(primary_key=True)
    spbu_id: Mapped[int] = mapped_column(
        ForeignKey("master_spbu.id", ondelete="CASCADE"), nullable=False
    )
    nama: Mapped[str] = mapped_column(String(200), nullable=False)
    deskripsi: Mapped[str | None] = mapped_column(Text, nullable=True)
    is_closed: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)

    pbs: Mapped[list["PB"]] = relationship(back_populates="project")


class PB(Base, TimestampMixin):
    __tablename__ = "pb"

    __table_args__ = (
        Index("ix_pb_spbu_id", "spbu_id"),
        Index("ix_pb_project_id", "project_id"),
        Index("ix_pb_status", "status"),
    )

    id: Mapped[int] = mapped_column(primary_key=True)
    spbu_id: Mapped[int] = mapped_column(
        ForeignKey("master_spbu.id", ondelete="CASCADE"), nullable=False
    )
    project_id: Mapped[int | None] = mapped_column(
        ForeignKey("pb_project.id", ondelete="SET NULL"), nullable=True
    )
    nomor: Mapped[str] = mapped_column(String(30), nullable=False, unique=True)
    judul: Mapped[str] = mapped_column(String(300), nullable=False)
    deskripsi: Mapped[str | None] = mapped_column(Text, nullable=True)
    is_kas_kecil: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
    status: Mapped[str] = mapped_column(String(20), nullable=False, default=StatusPB.DRAFT)
    attachment_url: Mapped[str | None] = mapped_column(String(500), nullable=True)

    created_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)

    # Manager: review + forward
    forwarded_by_id: Mapped[int | None] = mapped_column(
        ForeignKey("master_user.id", ondelete="SET NULL"), nullable=True
    )
    forwarded_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), 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)

    # Head of Management: final approve/reject
    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_head: Mapped[str | None] = mapped_column(Text, nullable=True)

    project: Mapped["Project | None"] = relationship(back_populates="pbs")
    items: Mapped[list["PBItem"]] = relationship(
        back_populates="pb", cascade="all, delete-orphan", order_by="PBItem.urutan"
    )
    created_by: Mapped["User | None"] = relationship(foreign_keys=[created_by_id])
    forwarded_by: Mapped["User | None"] = relationship(foreign_keys=[forwarded_by_id])
    recalled_by: Mapped["User | None"] = relationship(foreign_keys=[recalled_by_id])
    reviewed_by: Mapped["User | None"] = relationship(foreign_keys=[reviewed_by_id])
    expenses: Mapped[list["Expense"]] = relationship(back_populates="pb")


class PBItem(Base):
    __tablename__ = "pb_item"

    __table_args__ = (
        Index("ix_pb_item_pb_id", "pb_id"),
    )

    id: Mapped[int] = mapped_column(primary_key=True)
    pb_id: Mapped[int] = mapped_column(
        ForeignKey("pb.id", ondelete="CASCADE"), nullable=False
    )
    urutan: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    nama_item: Mapped[str] = mapped_column(String(300), nullable=False)
    qty_requested: Mapped[Decimal] = mapped_column(Numeric(15, 3), nullable=False)
    satuan: Mapped[str] = mapped_column(String(50), nullable=False)
    harga_satuan: Mapped[Decimal] = mapped_column(Numeric(15, 2), nullable=False)
    # total_estimasi = qty_requested × harga_satuan (computed on read, not stored)

    status: Mapped[str] = mapped_column(String(20), nullable=False, default=StatusPBItem.PENDING)
    qty_approved: Mapped[Decimal | None] = mapped_column(Numeric(15, 3), nullable=True)
    catatan_head: Mapped[str | None] = mapped_column(Text, nullable=True)

    pb: Mapped["PB"] = relationship(back_populates="items")
