"""Phase 5.8 — Fixed Assets 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 AssetStatus, DepreciationMethod, GUID


class AssetCategory(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
    __tablename__ = "asset_categories"

    code: Mapped[str] = mapped_column(String(50), nullable=False)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    default_useful_life_months: Mapped[int] = mapped_column(Integer, default=60, nullable=False)
    default_depreciation_method: Mapped[DepreciationMethod] = mapped_column(
        default=DepreciationMethod.STRAIGHT_LINE, nullable=False
    )
    is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)

    __table_args__ = (UniqueConstraint("tenant_id", "code", name="uq_asset_category_tenant_code"),)


class AssetGroup(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
    __tablename__ = "asset_groups"

    code: Mapped[str] = mapped_column(String(50), nullable=False)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    category_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)

    __table_args__ = (UniqueConstraint("tenant_id", "code", name="uq_asset_group_tenant_code"),)


class Asset(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
    __tablename__ = "assets"

    code: Mapped[str] = mapped_column(String(50), nullable=False)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    category_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    group_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    serial_number: Mapped[str | None] = mapped_column(String(100), nullable=True)
    location: Mapped[str | None] = mapped_column(String(255), nullable=True)
    department_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    cost_center_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    project_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    acquisition_date: Mapped[date | None] = mapped_column(Date, nullable=True)
    acquisition_cost: Mapped[Decimal] = mapped_column(Numeric(18, 4), default=Decimal("0"), nullable=False)
    current_book_value: Mapped[Decimal] = mapped_column(Numeric(18, 4), default=Decimal("0"), nullable=False)
    residual_value: Mapped[Decimal] = mapped_column(Numeric(18, 4), default=Decimal("0"), nullable=False)
    useful_life_months: Mapped[int] = mapped_column(Integer, default=60, nullable=False)
    depreciation_method: Mapped[DepreciationMethod] = mapped_column(
        default=DepreciationMethod.STRAIGHT_LINE, nullable=False
    )
    status: Mapped[AssetStatus] = mapped_column(default=AssetStatus.DRAFT, nullable=False)
    voucher_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)

    __table_args__ = (
        UniqueConstraint("tenant_id", "code", name="uq_asset_tenant_code"),
        Index("ix_assets_tenant_status", "tenant_id", "status"),
    )


class AssetDepreciation(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
    __tablename__ = "asset_depreciations"

    asset_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    fiscal_period_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    depreciation_date: Mapped[date] = mapped_column(Date, nullable=False)
    amount: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False)
    accumulated_depreciation: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False)
    book_value_after: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False)
    voucher_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)

    __table_args__ = (Index("ix_asset_depreciation_asset", "tenant_id", "asset_id"),)


class DepreciationSchedule(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
    __tablename__ = "depreciation_schedules"

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


class AssetTransfer(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
    __tablename__ = "asset_transfers"

    asset_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    transfer_date: Mapped[date] = mapped_column(Date, nullable=False)
    from_location: Mapped[str | None] = mapped_column(String(255), nullable=True)
    to_location: Mapped[str | None] = mapped_column(String(255), nullable=True)
    from_department_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    to_department_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    voucher_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)


class AssetDisposal(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
    __tablename__ = "asset_disposals"

    asset_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    disposal_date: Mapped[date] = mapped_column(Date, nullable=False)
    disposal_type: Mapped[str] = mapped_column(String(50), nullable=False)
    sale_amount: Mapped[Decimal | None] = mapped_column(Numeric(18, 4), nullable=True)
    gain_loss: Mapped[Decimal | None] = mapped_column(Numeric(18, 4), nullable=True)
    voucher_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)


class AssetRevaluation(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
    __tablename__ = "asset_revaluations"

    asset_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    revaluation_date: Mapped[date] = mapped_column(Date, nullable=False)
    old_book_value: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False)
    new_book_value: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False)
    difference: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False)
    voucher_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)


class AssetImpairment(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
    __tablename__ = "asset_impairments"

    asset_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    impairment_date: Mapped[date] = mapped_column(Date, nullable=False)
    impairment_amount: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False)
    reason: Mapped[str | None] = mapped_column(Text, nullable=True)
    voucher_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)


class AssetAccountingProfile(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
    __tablename__ = "asset_accounting_profiles"

    name: Mapped[str] = mapped_column(String(255), nullable=False)
    category_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    asset_account_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    depreciation_account_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    accumulated_depreciation_account_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    disposal_gain_account_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    disposal_loss_account_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    is_default: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)


class AssetHistory(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
    __tablename__ = "asset_history"

    asset_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    event_type: Mapped[str] = mapped_column(String(50), nullable=False)
    event_date: Mapped[date] = mapped_column(Date, nullable=False)
    description: Mapped[str | None] = mapped_column(Text, nullable=True)
    before_value: Mapped[str | None] = mapped_column(Text, nullable=True)
    after_value: Mapped[str | None] = mapped_column(Text, nullable=True)

    __table_args__ = (Index("ix_asset_history_asset", "tenant_id", "asset_id"),)


class AssetLocation(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
    __tablename__ = "asset_locations"

    code: Mapped[str] = mapped_column(String(50), nullable=False)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)

    __table_args__ = (UniqueConstraint("tenant_id", "code", name="uq_asset_location_tenant_code"),)
