import enum
from datetime import datetime

from sqlalchemy import DateTime, ForeignKey, Index, Integer, String, Text, func
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.orm import Mapped, mapped_column

from core.database import Base


class TaskStatus(str, enum.Enum):
    PENDING = "pending"
    ACTIVE = "active"
    COMPLETED = "completed"
    FAILED = "failed"


class TaskRun(Base):
    __tablename__ = "task_runs"
    __table_args__ = (
        Index("ix_core_task_runs_task_id", "task_id", unique=True),
        Index("ix_core_task_runs_tenant_updated", "tenant_id", "updated_at"),
        Index("ix_core_task_runs_tenant_status_updated", "tenant_id", "status", "updated_at"),
        Index("ix_core_task_runs_tenant_group_updated", "tenant_id", "task_group", "updated_at"),
        Index("ix_core_task_runs_tenant_company_updated", "tenant_id", "company_id", "updated_at"),
        {"schema": "core"},
    )

    id: Mapped[int] = mapped_column(Integer, primary_key=True)
    task_id: Mapped[str] = mapped_column(String(255), nullable=False)
    tenant_id: Mapped[int] = mapped_column(
        Integer, ForeignKey("core.tenants.id"), nullable=False, index=True
    )
    company_id: Mapped[int | None] = mapped_column(
        Integer, nullable=True, index=True
    )
    requested_by_user: Mapped[str | None] = mapped_column(String(255), nullable=True)
    task_name: Mapped[str] = mapped_column(String(255), nullable=False)
    task_group: Mapped[str] = mapped_column(String(100), nullable=False)
    task_origin: Mapped[str | None] = mapped_column(String(255), nullable=True)
    status: Mapped[TaskStatus] = mapped_column(
        String(20), nullable=False, default=TaskStatus.PENDING.value
    )
    celery_state_raw: Mapped[str] = mapped_column(String(30), nullable=False, default="PENDING")
    progress_current: Mapped[int | None] = mapped_column(Integer, nullable=True)
    progress_total: Mapped[int | None] = mapped_column(Integer, nullable=True)
    progress_percent: Mapped[float | None] = mapped_column(nullable=True)
    progress_message: Mapped[str | None] = mapped_column(String(500), nullable=True)
    retries: Mapped[int | None] = mapped_column(Integer, nullable=True)
    exception_type: Mapped[str | None] = mapped_column(String(255), nullable=True)
    exception_message: Mapped[str | None] = mapped_column(Text, nullable=True)
    traceback_excerpt: Mapped[str | None] = mapped_column(Text, nullable=True)
    result_summary: Mapped[dict | None] = mapped_column(JSONB, nullable=True)
    meta_payload: Mapped[dict | None] = mapped_column(JSONB, nullable=True)
    started_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
    finished_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), nullable=False, server_default=func.now()
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), nullable=False, server_default=func.now(), onupdate=func.now()
    )
