"""Phase 5.6 — Sales accounting integration domain models."""
from __future__ import annotations

import uuid
from datetime import date
from decimal import Decimal

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

from app.core.database import Base
from app.models.base import TenantMixin, TimestampMixin, UUIDPrimaryKeyMixin
from app.models.types import GUID, RevenueRecognitionMethod, SalesDocumentType


class SalesPostingProfile(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
    __tablename__ = "sales_posting_profiles"

    name: Mapped[str] = mapped_column(String(255), nullable=False)
    document_type: Mapped[SalesDocumentType] = mapped_column(nullable=False)
    revenue_account_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    receivable_account_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    cash_account_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    bank_account_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    discount_account_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    tax_account_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    deferred_revenue_account_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    rounding_account_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    is_default: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
    is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)

    __table_args__ = (
        UniqueConstraint("tenant_id", "name", name="uq_sales_profile_tenant_name"),
    )


class AccountingProfile(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
    __tablename__ = "accounting_profiles"

    name: Mapped[str] = mapped_column(String(255), nullable=False)
    profile_type: Mapped[str] = mapped_column(String(50), nullable=False)
    entity_type: Mapped[str] = mapped_column(String(50), nullable=False)
    entity_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    sales_posting_profile_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    config_data: Mapped[str | None] = mapped_column(Text, nullable=True)
    is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)

    __table_args__ = (
        Index("ix_accounting_profile_entity", "tenant_id", "entity_type", "entity_id"),
    )


class PostingRule(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
    __tablename__ = "posting_rules"

    name: Mapped[str] = mapped_column(String(255), nullable=False)
    document_type: Mapped[str] = mapped_column(String(50), nullable=False)
    source_module: Mapped[str] = mapped_column(String(50), nullable=False)
    debit_account_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    credit_account_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    condition_expression: Mapped[str | None] = mapped_column(Text, nullable=True)
    priority: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
    is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)

    __table_args__ = (
        Index("ix_posting_rules_tenant_module", "tenant_id", "source_module"),
    )


class SalesAccountingConfiguration(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
    __tablename__ = "sales_accounting_configurations"

    default_profile_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    auto_post_invoices: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
    auto_post_returns: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
    default_revenue_recognition: Mapped[RevenueRecognitionMethod] = mapped_column(
        default=RevenueRecognitionMethod.IMMEDIATE, nullable=False
    )

    __table_args__ = (
        UniqueConstraint("tenant_id", name="uq_sales_accounting_config_tenant"),
    )


class RevenueRecognition(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
    __tablename__ = "revenue_recognitions"

    source_document_type: Mapped[str] = mapped_column(String(50), nullable=False)
    source_document_id: Mapped[str] = mapped_column(String(100), nullable=False)
    method: Mapped[RevenueRecognitionMethod] = mapped_column(nullable=False)
    total_amount: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False)
    recognized_amount: Mapped[Decimal] = mapped_column(
        Numeric(18, 4), default=Decimal("0"), nullable=False
    )
    deferred_amount: Mapped[Decimal] = mapped_column(
        Numeric(18, 4), default=Decimal("0"), nullable=False
    )
    recognition_date: Mapped[date | None] = mapped_column(Date, nullable=True)
    voucher_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)

    __table_args__ = (
        Index("ix_revenue_recognition_source", "tenant_id", "source_document_type", "source_document_id"),
    )


class RevenueSchedule(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
    __tablename__ = "revenue_schedules"

    revenue_recognition_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    schedule_date: Mapped[date] = mapped_column(Date, nullable=False)
    amount: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False)
    is_recognized: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
    voucher_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)


class AccountingPreview(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
    __tablename__ = "accounting_previews"

    source_module: Mapped[str] = mapped_column(String(50), nullable=False)
    source_document_type: Mapped[str] = mapped_column(String(50), nullable=False)
    source_document_id: Mapped[str] = mapped_column(String(100), nullable=False)
    preview_data: Mapped[str] = mapped_column(Text, nullable=False)
    is_balanced: Mapped[bool] = mapped_column(Boolean, nullable=False)
    total_debit: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False)
    total_credit: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False)


class PostingSimulation(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
    __tablename__ = "posting_simulations"

    source_module: Mapped[str] = mapped_column(String(50), nullable=False)
    simulation_data: Mapped[str] = mapped_column(Text, nullable=False)
    result_data: Mapped[str | None] = mapped_column(Text, nullable=True)
    is_successful: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
    error_message: Mapped[str | None] = mapped_column(Text, nullable=True)
