"""POS Lite aggregates — Phase 12.4.

Lightweight point-of-sale shell: registers, shifts, tickets, and ticket
lines for small venue formats. No payment posting, no accounting entries.
"""
from __future__ import annotations

import uuid
from datetime import datetime

from sqlalchemy import DateTime, Index, Integer, String, Text, UniqueConstraint
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.types import JSON

from app.core.database import Base
from app.models.base import (
    ActorAuditMixin,
    SoftDeleteMixin,
    TenantMixin,
    TimestampMixin,
    UUIDPrimaryKeyMixin,
)
from app.models.types import GUID, LifecycleStatus, PosShiftStatus, PosTicketStatus


class PosRegister(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """A physical or virtual POS register within a venue."""

    __tablename__ = "pos_registers"

    venue_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    code: Mapped[str] = mapped_column(String(50), nullable=False)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    status: Mapped[LifecycleStatus] = mapped_column(
        default=LifecycleStatus.ACTIVE, nullable=False
    )
    description: Mapped[str | None] = mapped_column(Text, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id", "venue_id", "code", name="uq_pos_registers_tenant_venue_code"
        ),
        Index("ix_pos_registers_venue", "tenant_id", "venue_id"),
        Index("ix_pos_registers_status", "tenant_id", "status"),
        Index("ix_pos_registers_tenant_deleted", "tenant_id", "is_deleted"),
    )


class PosShift(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """A cashier shift opened against a register."""

    __tablename__ = "pos_shifts"

    venue_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    register_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    opened_by: Mapped[str | None] = mapped_column(String(100), nullable=True)
    status: Mapped[PosShiftStatus] = mapped_column(
        default=PosShiftStatus.OPEN, nullable=False
    )
    opened_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)
    closed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)

    __table_args__ = (
        Index("ix_pos_shifts_venue", "tenant_id", "venue_id"),
        Index("ix_pos_shifts_register", "tenant_id", "register_id"),
        Index("ix_pos_shifts_status", "tenant_id", "status"),
        Index("ix_pos_shifts_tenant_deleted", "tenant_id", "is_deleted"),
    )


class PosTicket(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """A sale ticket opened against a register / shift, optionally linked to a table or QR ordering session."""

    __tablename__ = "pos_tickets"

    venue_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    register_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    shift_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    table_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    ordering_session_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    code: Mapped[str] = mapped_column(String(50), nullable=False)
    status: Mapped[PosTicketStatus] = mapped_column(
        default=PosTicketStatus.DRAFT, nullable=False
    )
    currency_code: Mapped[str] = mapped_column(String(3), default="IRR", nullable=False)
    notes: Mapped[str | None] = mapped_column(Text, nullable=True)
    metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id", "venue_id", "code", name="uq_pos_tickets_tenant_venue_code"
        ),
        Index("ix_pos_tickets_venue", "tenant_id", "venue_id"),
        Index("ix_pos_tickets_register", "tenant_id", "register_id"),
        Index("ix_pos_tickets_shift", "tenant_id", "shift_id"),
        Index("ix_pos_tickets_status", "tenant_id", "status"),
        Index("ix_pos_tickets_tenant_deleted", "tenant_id", "is_deleted"),
    )


class PosTicketLine(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """A single menu-item line on a POS ticket."""

    __tablename__ = "pos_ticket_lines"

    venue_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    ticket_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    menu_item_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    quantity: Mapped[int] = mapped_column(Integer, default=1, nullable=False)
    unit_price: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
    currency_code: Mapped[str] = mapped_column(String(3), default="IRR", nullable=False)
    modifier_option_ids: Mapped[list | None] = mapped_column(JSON, nullable=True)
    line_notes: Mapped[str | None] = mapped_column(Text, nullable=True)
    sort_order: Mapped[int] = mapped_column(Integer, default=0, nullable=False)

    __table_args__ = (
        Index("ix_pos_ticket_lines_venue", "tenant_id", "venue_id"),
        Index("ix_pos_ticket_lines_ticket", "tenant_id", "ticket_id"),
        Index("ix_pos_ticket_lines_tenant_deleted", "tenant_id", "is_deleted"),
    )
