# #region MaintenanceModels [C:2] [TYPE Module] [SEMANTICS sqlalchemy, maintenance, banner, event, settings, model]
# @BRIEF SQLAlchemy models for the Maintenance Banner feature: event, banner, dashboard state, and settings.
# @LAYER Domain
# @RELATION DEPENDS_ON -> [EXT:Library:sqlalchemy]
# @RELATION DEPENDS_ON -> [MappingModels]
# @INVARIANT MaintenanceDashboardBanner has unique partial index on (environment_id, dashboard_id) WHERE status='active'
# @INVARIANT MaintenanceSettings is a singleton row (id='default') enforced by CheckConstraint

import enum
import uuid

from sqlalchemy import (
    JSON,
    CheckConstraint,
    Column,
    DateTime,
    Enum as SQLEnum,
    ForeignKey,
    Index,
    Integer,
    String,
    Text,
)
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func

from .mapping import Base


# #region MaintenanceEventStatus [C:1] [TYPE Class]
class MaintenanceEventStatus(str, enum.Enum):
    PENDING = "pending"
    APPLYING = "applying"
    ACTIVE = "active"
    PARTIAL = "partial"
    ENDING = "ending"
    COMPLETED = "completed"
    FAILED = "failed"
# #endregion MaintenanceEventStatus


# #region MaintenanceDashboardBannerStatus [C:1] [TYPE Class]
class MaintenanceDashboardBannerStatus(str, enum.Enum):
    ACTIVE = "active"
    REMOVED = "removed"
# #endregion MaintenanceDashboardBannerStatus


# #region MaintenanceDashboardStateStatus [C:1] [TYPE Class]
class MaintenanceDashboardStateStatus(str, enum.Enum):
    PENDING_APPLY = "pending_apply"
    ACTIVE = "active"
    REMOVING = "removing"
    REMOVED = "removed"
    APPLY_FAILED = "apply_failed"
    REMOVAL_FAILED = "removal_failed"
# #endregion MaintenanceDashboardStateStatus


# #region DashboardScope [C:1] [TYPE Class]
class DashboardScope(str, enum.Enum):
    PUBLISHED_ONLY = "published_only"
    DRAFT_ONLY = "draft_only"
    ALL = "all"
# #endregion DashboardScope


# #region MaintenanceEvent [C:1] [TYPE Class]
# @BRIEF A record of a maintenance event with table list, time window, status, and linked dashboard states.
# @RELATION DEPENDS_ON -> [MaintenanceDashboardState]
class MaintenanceEvent(Base):
    __tablename__ = "maintenance_events"

    id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4()), index=True)
    task_id = Column(String, nullable=True, index=True)
    environment_id = Column(String, nullable=False)
    tables = Column(JSON, nullable=False)
    start_time = Column(DateTime(timezone=True), nullable=False)
    end_time = Column(DateTime(timezone=True), nullable=True)
    message = Column(Text, nullable=True)
    status = Column(
        SQLEnum(MaintenanceEventStatus),
        nullable=False,
        default=MaintenanceEventStatus.PENDING,
        index=True,
    )
    created_at = Column(DateTime(timezone=True), server_default=func.now())
    updated_at = Column(
        DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
    )

    dashboard_states = relationship(
        "MaintenanceDashboardState",
        back_populates="maintenance_event",
        cascade="all, delete-orphan",
    )
# #endregion MaintenanceEvent


# #region MaintenanceDashboardBanner [C:1] [TYPE Class]
# @BRIEF The canonical "one chart per dashboard" entity. Unique partial index enforces single active banner per dashboard.
# @INVARIANT Unique partial index (environment_id, dashboard_id) WHERE status='active'
class MaintenanceDashboardBanner(Base):
    __tablename__ = "maintenance_dashboard_banners"

    id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4()), index=True)
    environment_id = Column(String, nullable=False)
    dashboard_id = Column(Integer, nullable=False, index=True)
    chart_id = Column(Integer, nullable=True)
    banner_text = Column(Text, nullable=True)
    status = Column(
        SQLEnum(MaintenanceDashboardBannerStatus),
        nullable=False,
        default=MaintenanceDashboardBannerStatus.ACTIVE,
    )
    created_at = Column(DateTime(timezone=True), server_default=func.now())
    updated_at = Column(
        DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
    )

    dashboard_states = relationship(
        "MaintenanceDashboardState", back_populates="banner"
    )

    __table_args__ = (
        Index(
            "ix_banner_unique_active",
            "environment_id",
            "dashboard_id",
            unique=True,
            postgresql_where=(status == "active"),
        ),
    )
# #endregion MaintenanceDashboardBanner


# #region MaintenanceDashboardState [C:1] [TYPE Class]
# @BRIEF Links a maintenance event to a dashboard via a banner. Tracks per-dashboard-per-event lifecycle.
# @RELATION DEPENDS_ON -> [MaintenanceEvent]
# @RELATION DEPENDS_ON -> [MaintenanceDashboardBanner]
class MaintenanceDashboardState(Base):
    __tablename__ = "maintenance_dashboard_states"

    id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4()), index=True)
    event_id = Column(
        String, ForeignKey("maintenance_events.id"), nullable=False, index=True
    )
    dashboard_id = Column(Integer, nullable=False, index=True)
    banner_id = Column(
        String,
        ForeignKey("maintenance_dashboard_banners.id"),
        nullable=True,
    )
    status = Column(
        SQLEnum(MaintenanceDashboardStateStatus),
        nullable=False,
        default=MaintenanceDashboardStateStatus.PENDING_APPLY,
    )
    created_at = Column(DateTime(timezone=True), server_default=func.now())
    updated_at = Column(
        DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
    )

    maintenance_event = relationship(
        "MaintenanceEvent", back_populates="dashboard_states"
    )
    banner = relationship(
        "MaintenanceDashboardBanner", back_populates="dashboard_states"
    )

    __table_args__ = (
        Index("ix_mds_dashboard_status", "dashboard_id", "status"),
    )
# #endregion MaintenanceDashboardState


# #region MaintenanceSettings [C:1] [TYPE Class]
# @BRIEF Single-row maintenance mode configuration. Enforces singleton via CheckConstraint(id='default').
# @INVARIANT id must always be 'default' — enforced by CheckConstraint
class MaintenanceSettings(Base):
    __tablename__ = "maintenance_settings"

    id = Column(String, primary_key=True, default="default")
    target_environment_id = Column(String, nullable=False)
    display_timezone = Column(String, nullable=False, default="UTC")
    banner_template = Column(
        Text,
        nullable=False,
        default=(
            '<div style="background:#FFF3E0;padding:16px;border-left:4px solid #FF9800;border-radius:4px">\n\n'
            "## ⚠️ Технические работы\n\n"
            "{message}\n\n"
            "**Начало:** {start_time}\n"
            "**Конец:** {end_time}\n\n"
            "*Данные могут быть неполными или временно недоступны.*\n\n"
            "</div>"
        ),
    )
    dashboard_scope = Column(
        SQLEnum(DashboardScope),
        nullable=False,
        default=DashboardScope.PUBLISHED_ONLY,
    )
    excluded_dashboard_ids = Column(JSON, nullable=False, default=list)
    forced_dashboard_ids = Column(JSON, nullable=False, default=list)
    updated_at = Column(
        DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
    )

    __table_args__ = (
        CheckConstraint("id = 'default'", name="ck_settings_singleton"),
    )
# #endregion MaintenanceSettings

# #endregion MaintenanceModels
