"""Operational models — LaporanShift and PenjualanNozzle."""

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

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

from app.models.base import Base, TimestampMixin


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


class LaporanShift(Base, TimestampMixin):
    """One sales/shift report per SPBU × shift × date."""

    __tablename__ = "laporan_shift"

    __table_args__ = (
        UniqueConstraint("spbu_id", "shift_id", "tanggal", name="uq_laporan_shift_spbu_shift_tanggal"),
        Index("ix_laporan_shift_spbu_tanggal", "spbu_id", "tanggal"),
    )

    id: Mapped[int] = mapped_column(primary_key=True)
    spbu_id: Mapped[int] = mapped_column(
        ForeignKey("master_spbu.id", ondelete="CASCADE"), nullable=False, index=True
    )
    shift_id: Mapped[int] = mapped_column(
        ForeignKey("master_spbu_shift.id", ondelete="RESTRICT"), nullable=False, index=True
    )
    tanggal: Mapped[date] = mapped_column(Date, nullable=False)
    status: Mapped[StatusLaporan] = mapped_column(
        String(20), nullable=False, default=StatusLaporan.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)
    unlock_reason: Mapped[str | None] = mapped_column(Text, 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
    )
    # Recall audit — set when operator pulls back a SUBMITTED laporan to DRAFT
    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
    )
    # Foto referensi yang diupload saat input dari foto (arsip di GDrive)
    source_foto_url: Mapped[str | None] = mapped_column(Text, nullable=True)

    # Cash on hand — denomination amounts (Rupiah total per pecahan)
    kas_100k: Mapped[Decimal] = mapped_column(Numeric(15, 3), nullable=False, default=0)
    kas_50k: Mapped[Decimal] = mapped_column(Numeric(15, 3), nullable=False, default=0)
    kas_20k: Mapped[Decimal] = mapped_column(Numeric(15, 3), nullable=False, default=0)
    kas_10k: Mapped[Decimal] = mapped_column(Numeric(15, 3), nullable=False, default=0)
    kas_5k: Mapped[Decimal] = mapped_column(Numeric(15, 3), nullable=False, default=0)
    kas_2k: Mapped[Decimal] = mapped_column(Numeric(15, 3), nullable=False, default=0)
    kas_1k: Mapped[Decimal] = mapped_column(Numeric(15, 3), nullable=False, default=0)
    kas_logam: Mapped[Decimal] = mapped_column(Numeric(15, 3), nullable=False, default=0)
    # Non-cash payment totals
    pembayaran_kartu: Mapped[Decimal] = mapped_column(Numeric(15, 3), nullable=False, default=0)
    pembayaran_qr: Mapped[Decimal] = mapped_column(Numeric(15, 3), nullable=False, default=0)
    pembayaran_instansi: Mapped[Decimal] = mapped_column(Numeric(15, 3), nullable=False, default=0)

    # relationships
    penjualan_nozzle: Mapped[list["PenjualanNozzle"]] = relationship(
        back_populates="laporan", cascade="all, delete-orphan"
    )
    spbu: Mapped["Spbu"] = relationship(foreign_keys=[spbu_id])
    shift: Mapped["Shift"] = relationship(foreign_keys=[shift_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])


class PenjualanNozzle(Base):
    """One sales row per nozzle inside a LaporanShift."""

    __tablename__ = "penjualan_nozzle"

    __table_args__ = (
        Index("ix_penjualan_nozzle_laporan_shift_id", "laporan_shift_id"),
    )

    id: Mapped[int] = mapped_column(primary_key=True)
    laporan_shift_id: Mapped[int] = mapped_column(
        ForeignKey("laporan_shift.id", ondelete="CASCADE"), nullable=False
    )
    nozzle_id: Mapped[int] = mapped_column(
        ForeignKey("master_spbu_nozzle.id", ondelete="RESTRICT"), nullable=False
    )
    # Both manual (mechanical meter) and digital readings are recorded
    teller_awal_manual: Mapped[Decimal] = mapped_column(Numeric(15, 3), nullable=False)
    teller_akhir_manual: Mapped[Decimal] = mapped_column(Numeric(15, 3), nullable=False)
    teller_awal_digital: Mapped[Decimal] = mapped_column(Numeric(15, 3), nullable=False)
    teller_akhir_digital: Mapped[Decimal] = mapped_column(Numeric(15, 3), nullable=False)
    flag_reset_teller: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
    # volume is computed from the primary_teller of the nozzle at save time
    volume: Mapped[Decimal] = mapped_column(Numeric(15, 3), nullable=False)
    harga_jual: Mapped[Decimal] = mapped_column(Numeric(15, 3), nullable=False)
    nilai: Mapped[Decimal] = mapped_column(Numeric(15, 3), nullable=False)

    # relationships
    laporan: Mapped["LaporanShift"] = relationship(back_populates="penjualan_nozzle")
    nozzle: Mapped["Nozzle"] = relationship(foreign_keys=[nozzle_id])


class StockAdjustment(Base, TimestampMixin):
    """One sounding record per SPBU × shift × date. Represents starting stock for that shift."""

    __tablename__ = "stock_adjustment"

    __table_args__ = (
        UniqueConstraint("spbu_id", "shift_id", "tanggal", name="uq_stock_adj_spbu_shift_tanggal"),
        Index("ix_stock_adj_spbu_tanggal", "spbu_id", "tanggal"),
    )

    id: Mapped[int] = mapped_column(primary_key=True)
    spbu_id: Mapped[int] = mapped_column(
        ForeignKey("master_spbu.id", ondelete="CASCADE"), nullable=False, index=True
    )
    shift_id: Mapped[int] = mapped_column(
        ForeignKey("master_spbu_shift.id", ondelete="RESTRICT"), nullable=False, index=True
    )
    tanggal: Mapped[date] = mapped_column(Date, nullable=False)
    status: Mapped[StatusLaporan] = mapped_column(
        String(20), nullable=False, default=StatusLaporan.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)
    unlock_reason: Mapped[str | None] = mapped_column(Text, 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
    )
    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
    )

    # relationships
    items: Mapped[list["StockAdjustmentItem"]] = relationship(
        back_populates="stock_adjustment", cascade="all, delete-orphan"
    )
    spbu: Mapped["Spbu"] = relationship(foreign_keys=[spbu_id])
    shift: Mapped["Shift"] = relationship(foreign_keys=[shift_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])


class StockAdjustmentItem(Base):
    """One sounding row per tank inside a StockAdjustment."""

    __tablename__ = "stock_adjustment_item"

    __table_args__ = (
        Index("ix_stock_adj_item_adj_id", "stock_adjustment_id"),
    )

    id: Mapped[int] = mapped_column(primary_key=True)
    stock_adjustment_id: Mapped[int] = mapped_column(
        ForeignKey("stock_adjustment.id", ondelete="CASCADE"), nullable=False
    )
    tangki_id: Mapped[int] = mapped_column(
        ForeignKey("master_spbu_tangki.id", ondelete="RESTRICT"), nullable=False
    )
    # Manual dipstick (cm stick / sounding rod) — optional per tank
    dipstick_manual_mm: Mapped["Decimal | None"] = mapped_column(Numeric(10, 2), nullable=True)
    volume_manual_liter: Mapped["Decimal | None"] = mapped_column(Numeric(15, 3), nullable=True)
    # Digital sensor reading — always required
    dipstick_digital_mm: Mapped["Decimal | None"] = mapped_column(Numeric(10, 2), nullable=True)
    volume_digital_liter: Mapped["Decimal | None"] = mapped_column(Numeric(15, 3), nullable=True)
    # Final volume: manual if available, else digital
    volume_final_liter: Mapped["Decimal | None"] = mapped_column(Numeric(15, 3), nullable=True)

    # relationships
    stock_adjustment: Mapped["StockAdjustment"] = relationship(back_populates="items")
    tangki: Mapped["Tangki"] = relationship(foreign_keys=[tangki_id])
    fotos: Mapped[list["StockAdjustmentItemFoto"]] = relationship(
        back_populates="item", cascade="all, delete-orphan"
    )


class StockAdjustmentItemFoto(Base):
    """Photo evidence for a single tank sounding (manual stick or digital display)."""

    __tablename__ = "stock_adjustment_item_foto"

    __table_args__ = (
        Index("ix_stock_adj_item_foto_item_id", "stock_adjustment_item_id"),
    )

    id: Mapped[int] = mapped_column(primary_key=True)
    stock_adjustment_item_id: Mapped[int] = mapped_column(
        ForeignKey("stock_adjustment_item.id", ondelete="CASCADE"), nullable=False
    )
    tipe: Mapped[str] = mapped_column(String(20), nullable=False)  # 'manual' | 'digital'
    url: Mapped[str] = mapped_column(String(500), nullable=False)
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default="now()", nullable=False
    )

    item: Mapped["StockAdjustmentItem"] = relationship(back_populates="fotos")


# Avoid circular imports
from app.models.spbu import Nozzle, Shift, Spbu, Tangki  # noqa: E402, F401
from app.models.user import User  # noqa: E402, F401
