"""مدل‌های رجیستری سرویس/ماژول و توکن‌های داخلی سرویس.

- ServiceRegistry: ثبت سرویس‌های داخلی آینده و آدرس‌های آن‌ها.
- ModuleRegistry: ماژول‌های قابل فعال/غیرفعال‌سازی برای tenantها.
- TenantModuleAccess: وضعیت فعال بودن هر ماژول برای هر tenant.
- InternalServiceToken: توکن امن ارتباط بین سرویس‌ها (hash ذخیره می‌شود).
"""
from __future__ import annotations

import uuid
from datetime import datetime

from sqlalchemy import Boolean, DateTime
from sqlalchemy import Enum as SAEnum
from sqlalchemy import ForeignKey, Index, String, Text, UniqueConstraint, func
from sqlalchemy.orm import Mapped, mapped_column

from app.core.database import Base
from app.models.base import UUIDPrimaryKeyMixin
from app.models.enums import ServiceStatus
from app.models.types import GUID


class ServiceRegistry(UUIDPrimaryKeyMixin, Base):
    __tablename__ = "service_registry"

    service_key: Mapped[str] = mapped_column(String(100), nullable=False, unique=True)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    base_url: Mapped[str | None] = mapped_column(String(500), nullable=True)
    status: Mapped[ServiceStatus] = mapped_column(
        SAEnum(ServiceStatus, name="service_status"),
        default=ServiceStatus.ACTIVE,
        nullable=False,
    )
    health_check_url: Mapped[str | None] = mapped_column(String(500), nullable=True)
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now(), nullable=False
    )

    __table_args__ = (Index("ix_service_registry_service_key", "service_key", unique=True),)


class ModuleRegistry(UUIDPrimaryKeyMixin, Base):
    __tablename__ = "module_registry"

    module_key: Mapped[str] = mapped_column(String(100), nullable=False, unique=True)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    description: Mapped[str | None] = mapped_column(Text, nullable=True)
    # ماژول سیستمی همیشه فعال است و توسط tenant قابل غیرفعال‌سازی نیست.
    is_system_module: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
    is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)

    __table_args__ = (Index("ix_module_registry_module_key", "module_key", unique=True),)


class TenantModuleAccess(UUIDPrimaryKeyMixin, Base):
    __tablename__ = "tenant_module_access"

    tenant_id: Mapped[uuid.UUID] = mapped_column(
        GUID(), ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False
    )
    module_id: Mapped[uuid.UUID] = mapped_column(
        GUID(), ForeignKey("module_registry.id", ondelete="CASCADE"), nullable=False
    )
    is_enabled: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
    enabled_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
    disabled_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)

    __table_args__ = (
        UniqueConstraint("tenant_id", "module_id", name="uq_tenant_module_access"),
        Index("ix_tenant_module_access_tenant_id", "tenant_id"),
    )


class InternalServiceToken(UUIDPrimaryKeyMixin, Base):
    __tablename__ = "internal_service_tokens"

    service_key: Mapped[str] = mapped_column(String(100), nullable=False)
    # فقط hash توکن ذخیره می‌شود، نه خود توکن.
    token_hash: Mapped[str] = mapped_column(String(255), nullable=False, unique=True)
    # اسکوپ‌ها به‌صورت رشته‌ی جداشده با کاما یا فضای مجاز.
    scopes: Mapped[str | None] = mapped_column(Text, nullable=True)
    expires_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
    is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now(), nullable=False
    )

    __table_args__ = (
        Index("ix_internal_service_tokens_service_key", "service_key"),
        Index("ix_internal_service_tokens_token_hash", "token_hash", unique=True),
    )
