"""engagements + compensation_terms + rate_overrides (02-domain-model.md §2).

Roles live on relationships, not on parties. An engagement is a
directional, typed working relationship between two parties, recorded in
one tenant's books. Ended engagements are never deleted.

R1 worker-terms model (the `kind` column): both sides of a worker's
economics live as two term rows on the worker's OWN engagement — a
cost-kind term (what the tenant pays) and a billout-kind term (what the
tenant bills onward). Recomposing billout onto partnership hops is R4.

rate_overrides stays its own table in R1 (judgment #25): project-wide
(worker NULL) and pct overrides are resolution-time rules that don't
flatten into static per-engagement terms.
"""

import uuid
from datetime import date, datetime

from sqlalchemy import (
    CHAR,
    Boolean,
    CheckConstraint,
    Date,
    DateTime,
    ForeignKey,
    Index,
    Numeric,
    Text,
    Uuid,
    func,
    text,
)
from sqlalchemy.orm import Mapped, mapped_column

from app.models.base import ZERO_UUID, Base

ENGAGEMENT_TYPES = (
    "subcontract",
    "freelance",
    "partnership",
    "referral",
    "referral_pass_through",
    "direct_client",
    "employment",
    "official_partnership",
)

COMPENSATION_MODELS = (
    "hourly",
    "per_unit",
    "fixed_price",
    "prepaid_block",
    "profit_share",
    "commission",
    "gross_percentage",
    "salary",
)


def _in_list(column: str, values: tuple[str, ...]) -> str:
    quoted = ", ".join(f"'{v}'" for v in values)
    return f"{column} IN ({quoted})"


class Engagement(Base):
    __tablename__ = "engagements"
    __table_args__ = (
        CheckConstraint(_in_list("type", ENGAGEMENT_TYPES), name="ck_engagements_type"),
        CheckConstraint(
            "transparency IN ('transparent', 'opaque')",
            name="ck_engagements_transparency",
        ),
        Index("ix_engagements_tenant", "tenant_id"),
        Index("ix_engagements_party_a", "party_a_id"),
        Index("ix_engagements_party_b", "party_b_id"),
    )

    id: Mapped[uuid.UUID] = mapped_column(Uuid(), primary_key=True, default=uuid.uuid4)
    tenant_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("tenants.id"))
    type: Mapped[str] = mapped_column(Text())
    party_a_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("parties.id"))
    party_b_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("parties.id"))
    role_a: Mapped[str] = mapped_column(Text())
    role_b: Mapped[str] = mapped_column(Text())
    # the NewGrowth pattern — subcontractor poses as prime
    transparency: Mapped[str] = mapped_column(Text(), default="transparent")
    started_on: Mapped[date | None] = mapped_column(Date())
    # ends the WORKING relationship, never money obligations derived from it
    ended_on: Mapped[date | None] = mapped_column(Date())
    # R1 parity capability: today's canManageImports, carried onto the
    # worker's engagement (02 §4 parity mapping).
    can_manage_imports: Mapped[bool] = mapped_column(Boolean(), default=False)
    # import-mapping config: legacy team_members.consolidate_as (02 §7).
    consolidate_as: Mapped[str | None] = mapped_column(Text())
    notes: Mapped[str | None] = mapped_column(Text())
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now()
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
    )


class CompensationTerm(Base):
    __tablename__ = "compensation_terms"
    __table_args__ = (
        CheckConstraint(
            "kind IN ('cost', 'billout')", name="ck_compensation_terms_kind"
        ),
        CheckConstraint(
            _in_list("model", COMPENSATION_MODELS), name="ck_compensation_terms_model"
        ),
        # a rate is quoted in exactly one currency (02 §3)
        CheckConstraint(
            "(rate_amount IS NULL) = (currency IS NULL)",
            name="ck_compensation_terms_currency_pair",
        ),
        Index("ix_compensation_terms_engagement", "engagement_id"),
        Index("ix_compensation_terms_project", "project_id"),
    )

    id: Mapped[uuid.UUID] = mapped_column(Uuid(), primary_key=True, default=uuid.uuid4)
    engagement_id: Mapped[uuid.UUID] = mapped_column(
        ForeignKey("engagements.id", ondelete="CASCADE")
    )
    kind: Mapped[str] = mapped_column(Text())  # cost | billout (R1 worker model)
    model: Mapped[str] = mapped_column(Text())
    # NULL = never priced; 0.00 = a real zero-rate term (judgment #19).
    rate_amount: Mapped[float | None] = mapped_column(Numeric(12, 2))
    currency: Mapped[str | None] = mapped_column(CHAR(3))
    percentage: Mapped[float | None] = mapped_column(Numeric(7, 4))
    # NULL = default for the engagement; set = project-specific override
    project_id: Mapped[uuid.UUID | None] = mapped_column(
        ForeignKey("projects.id", ondelete="CASCADE")
    )
    effective_from: Mapped[date] = mapped_column(Date())  # rate history append-only
    effective_to: Mapped[date | None] = mapped_column(Date())
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now()
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
    )


class RateOverride(Base):
    __tablename__ = "rate_overrides"
    __table_args__ = (
        # absolute XOR pct — carried verbatim from the legacy table
        CheckConstraint(
            "(override_rate IS NOT NULL AND override_pct IS NULL)"
            " OR (override_rate IS NULL AND override_pct IS NOT NULL)",
            name="ck_rate_overrides_one_kind",
        ),
        CheckConstraint(
            "override_rate IS NULL OR override_rate >= 0",
            name="ck_rate_overrides_rate_nonnegative",
        ),
        # only the absolute rate is money; pct is a signed modifier
        CheckConstraint(
            "(override_rate IS NULL) = (currency IS NULL)",
            name="ck_rate_overrides_currency_pair",
        ),
        # max one project-wide (worker NULL) rule per project, one rule per
        # (project, worker) — zero-uuid sentinel carried from legacy.
        Index(
            "uq_rate_overrides_project_worker",
            "project_id",
            text(f"coalesce(worker_party_id, '{ZERO_UUID}')"),
            unique=True,
        ),
        Index("ix_rate_overrides_project", "project_id"),
        Index("ix_rate_overrides_worker", "worker_party_id"),
    )

    id: Mapped[uuid.UUID] = mapped_column(Uuid(), primary_key=True, default=uuid.uuid4)
    tenant_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("tenants.id"))
    project_id: Mapped[uuid.UUID] = mapped_column(
        ForeignKey("projects.id", ondelete="CASCADE")
    )
    # NULL = project-wide rule (applies to every worker, incl. added later)
    worker_party_id: Mapped[uuid.UUID | None] = mapped_column(
        ForeignKey("parties.id", ondelete="CASCADE")
    )
    override_rate: Mapped[float | None] = mapped_column(Numeric(12, 2))
    currency: Mapped[str | None] = mapped_column(CHAR(3))
    # signed % on the worker's fallback rate (-20 = 20% discount)
    override_pct: Mapped[float | None] = mapped_column(Numeric(7, 4))
    notes: Mapped[str | None] = mapped_column(Text())
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now()
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
    )
