"""QR Menu & QR Ordering shells — Phase 12.2.

Public QR surfaces and guest ordering/cart shells consuming the digital menu catalog.
POS / kitchen / payment / reservation engines are out of scope.
"""
from __future__ import annotations

import uuid

from sqlalchemy import (
    Boolean,
    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 (
    CartStatus,
    GUID,
    LifecycleStatus,
    OrderingSessionStatus,
    QrSessionStatus,
    QrTargetType,
)


class QrCode(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """QR code mapping token/slug to venue + optional menu/table targets."""

    __tablename__ = "qr_codes"

    venue_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    code: Mapped[str] = mapped_column(String(50), nullable=False)
    token: Mapped[str] = mapped_column(String(64), nullable=False)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    description: Mapped[str | None] = mapped_column(Text, nullable=True)
    status: Mapped[LifecycleStatus] = mapped_column(
        default=LifecycleStatus.ACTIVE, nullable=False
    )
    target_type: Mapped[QrTargetType] = mapped_column(
        default=QrTargetType.MENU, nullable=False
    )
    menu_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    dining_area_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    table_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    ordering_enabled: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
    metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint("tenant_id", "venue_id", "code", name="uq_qr_codes_tenant_code"),
        UniqueConstraint("tenant_id", "token", name="uq_qr_codes_tenant_token"),
        Index("ix_qr_codes_venue", "tenant_id", "venue_id"),
        Index("ix_qr_codes_token", "tenant_id", "token"),
        Index("ix_qr_codes_tenant_deleted", "tenant_id", "is_deleted"),
    )


class QrMenuSession(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """Guest browse session opened via QR — catalog view shell only."""

    __tablename__ = "qr_menu_sessions"

    venue_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    qr_code_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    menu_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    table_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    session_token: Mapped[str] = mapped_column(String(64), nullable=False)
    status: Mapped[QrSessionStatus] = mapped_column(
        default=QrSessionStatus.OPEN, nullable=False
    )
    locale: Mapped[str | None] = mapped_column(String(16), nullable=True)
    guest_label: Mapped[str | None] = mapped_column(String(255), nullable=True)
    metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id", "session_token", name="uq_qr_menu_sessions_token"
        ),
        Index("ix_qr_menu_sessions_qr", "tenant_id", "qr_code_id"),
        Index("ix_qr_menu_sessions_venue", "tenant_id", "venue_id"),
        Index("ix_qr_menu_sessions_tenant_deleted", "tenant_id", "is_deleted"),
    )


class QrOrderingSession(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """Guest ordering session shell — not a POS/kitchen ticket."""

    __tablename__ = "qr_ordering_sessions"

    venue_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    qr_code_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    qr_menu_session_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    menu_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    table_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    session_token: Mapped[str] = mapped_column(String(64), nullable=False)
    status: Mapped[OrderingSessionStatus] = mapped_column(
        default=OrderingSessionStatus.DRAFT, nullable=False
    )
    guest_label: Mapped[str | None] = mapped_column(String(255), nullable=True)
    notes: Mapped[str | None] = mapped_column(Text, nullable=True)
    metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id", "session_token", name="uq_qr_ordering_sessions_token"
        ),
        Index("ix_qr_ordering_sessions_qr", "tenant_id", "qr_code_id"),
        Index("ix_qr_ordering_sessions_venue", "tenant_id", "venue_id"),
        Index("ix_qr_ordering_sessions_tenant_deleted", "tenant_id", "is_deleted"),
    )


class Cart(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """Cart shell bound to an ordering session — no payment posting."""

    __tablename__ = "carts"

    venue_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    ordering_session_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    status: Mapped[CartStatus] = mapped_column(default=CartStatus.ACTIVE, 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",
            "ordering_session_id",
            name="uq_carts_ordering_session",
        ),
        Index("ix_carts_session", "tenant_id", "ordering_session_id"),
        Index("ix_carts_venue", "tenant_id", "venue_id"),
        Index("ix_carts_tenant_deleted", "tenant_id", "is_deleted"),
    )


class CartLine(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """Cart line with menu item + optional modifier option refs and price snapshot."""

    __tablename__ = "cart_lines"

    venue_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    cart_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_cart_lines_cart", "tenant_id", "cart_id"),
        Index("ix_cart_lines_item", "tenant_id", "menu_item_id"),
        Index("ix_cart_lines_tenant_deleted", "tenant_id", "is_deleted"),
    )
