from __future__ import annotations

from datetime import datetime
from typing import Optional

from sqlalchemy import Boolean, DateTime, ForeignKey, Integer, String, Text
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.sql import func

from src.apps.base.models.base import Base


class SchedulerConfig(Base):
    """
    Persisted configuration for each known Celery Beat / scheduler task.

    One row per task_name (UNIQUE).  Admins can toggle is_enabled, change
    schedule_expression, adjust alert_threshold_ms, and set log_retention_days
    via the Scheduler Admin UI without a code deploy.
    """

    __tablename__ = "scheduler_configs"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)

    # Dotted task identifier that matches Celery task name / beat schedule key
    task_name: Mapped[str] = mapped_column(String(200), unique=True, nullable=False)

    # Human-readable label shown in the admin UI
    display_name: Mapped[str] = mapped_column(String(200), nullable=False)

    # Optional long description of what the task does
    description: Mapped[Optional[str]] = mapped_column(Text, nullable=True)

    # Cron / interval expression (informational; actual schedule lives in beat)
    schedule_expression: Mapped[str] = mapped_column(String(100), nullable=False)

    # Whether this task is allowed to run (checked by the task itself on entry)
    is_enabled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)

    # If True, the manual-trigger UI exposes a merchant filter
    supports_merchant_filter: Mapped[bool] = mapped_column(
        Boolean, nullable=False, default=False
    )

    # Warn in the log when a run exceeds this many milliseconds (NULL = no alert)
    alert_threshold_ms: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)

    # How many days of scheduler_logs rows to retain for this task
    log_retention_days: Mapped[int] = mapped_column(Integer, nullable=False, default=90)

    # Admin who last changed this config row
    last_modified_by_admin_id: Mapped[Optional[int]] = mapped_column(
        Integer, ForeignKey("users.id"), nullable=True
    )

    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now(), nullable=False
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        server_default=func.now(),
        onupdate=func.now(),
        nullable=False,
    )

    # Relationships
    last_modified_by: Mapped[Optional["User"]] = relationship(  # type: ignore[name-defined]
        "User", foreign_keys=[last_modified_by_admin_id], lazy="select"
    )
