#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
模块名称：scheduled_task.py
模块描述：定时任务数据库模型定义（UI 自动化 + 安全测试共用）

作者：czj
创建日期：2026-08-19
最后修改：2026-08-19
"""

from datetime import datetime
from typing import Optional
from sqlalchemy import String, Boolean, Integer, JSON, DateTime
from sqlalchemy.orm import Mapped, mapped_column

from app.database import Base


class ScheduledTask(Base):
    """
    定时任务数据库模型

    存储定时任务的定义：选择哪些模块执行、周期设置、启用状态等。
    每次到期触发会创建一条 Execution 记录（trigger_type=scheduled,
    trigger_by=任务名），执行完成后自动生成报告到报告中心。
    通过 case_type 字段区分 UI 自动化定时任务与安全测试定时任务。

    Attributes:
        id (str): 任务唯一标识
        name (str): 任务名称（作为执行记录的 trigger_by）
        case_type (str): 用例类型 (ui/security)
        config_id (str): 安全测试配置ID（case_type=security 时使用）
        enabled (bool): 是否启用
        module_ids (list): 选中的模块 ID 列表
        schedule_type (str): 周期模式 (interval/daily/weekly)
        interval_value (int): 间隔值（schedule_type=interval）
        interval_unit (str): 间隔单位 (minutes/hours/days)
        run_time (str): 执行时间 HH:MM（schedule_type=daily/weekly）
        weekdays (list): 星期 [0-6]（schedule_type=weekly）
        auto_report (bool): 执行完成后是否自动生成报告
        last_run_at (datetime): 最近一次触发时间
        next_run_at (datetime): 下次触发时间
        run_count (int): 累计触发次数
        created_at (datetime): 创建时间
        updated_at (datetime): 更新时间

    Example:
        >>> task = ScheduledTask(
        ...     id="scheduled_abc123",
        ...     name="每日安全扫描",
        ...     case_type="security",
        ...     config_id="sec_cfg_default",
        ...     module_ids=["sec_api01"],
        ...     schedule_type="daily",
        ...     run_time="22:00",
        ... )
    """

    __tablename__ = "scheduled_tasks"

    id: Mapped[str] = mapped_column(String(64), primary_key=True, comment="任务ID")
    name: Mapped[str] = mapped_column(String(100), nullable=False, comment="任务名称")
    case_type: Mapped[str] = mapped_column(
        String(20), default="ui", comment="用例类型: ui/security"
    )
    config_id: Mapped[Optional[str]] = mapped_column(
        String(64), nullable=True, default=None, comment="安全测试配置ID（security时使用）"
    )
    enabled: Mapped[bool] = mapped_column(
        Boolean, default=True, comment="是否启用"
    )
    module_ids: Mapped[list] = mapped_column(
        JSON, default=list, comment="选中的模块ID列表"
    )
    schedule_type: Mapped[str] = mapped_column(
        String(20),
        default="interval",
        comment="周期模式: interval(按间隔)/daily(每天定时)/weekly(每周定时)"
    )
    interval_value: Mapped[int] = mapped_column(
        Integer, default=0, comment="间隔值（schedule_type=interval）"
    )
    interval_unit: Mapped[str] = mapped_column(
        String(10),
        default="minutes",
        comment="间隔单位: minutes/hours/days"
    )
    run_time: Mapped[str] = mapped_column(
        String(5), default="", comment="执行时间 HH:MM（daily/weekly）"
    )
    weekdays: Mapped[list] = mapped_column(
        JSON, default=list, comment="星期 [0-6]（weekly）"
    )
    auto_report: Mapped[bool] = mapped_column(
        Boolean, default=True, comment="执行完成后自动生成报告"
    )
    last_run_at: Mapped[Optional[datetime]] = mapped_column(
        DateTime, nullable=True, default=None, comment="最近一次触发时间"
    )
    next_run_at: Mapped[Optional[datetime]] = mapped_column(
        DateTime, nullable=True, default=None, comment="下次触发时间"
    )
    run_count: Mapped[int] = mapped_column(
        Integer, default=0, comment="累计触发次数"
    )
    created_at: Mapped[datetime] = mapped_column(
        DateTime, default=datetime.utcnow, comment="创建时间"
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime,
        default=datetime.utcnow,
        onupdate=datetime.utcnow,
        comment="更新时间"
    )

    def __repr__(self) -> str:
        return f"<ScheduledTask(id={self.id}, name={self.name}, enabled={self.enabled})>"

    def to_dict(self) -> dict:
        """
        转换为字典

        Returns:
            dict: 定时任务数据字典
        """
        return {
            "id": self.id,
            "name": self.name,
            "case_type": self.case_type,
            "config_id": self.config_id,
            "enabled": self.enabled,
            "module_ids": self.module_ids or [],
            "schedule_type": self.schedule_type,
            "interval_value": self.interval_value,
            "interval_unit": self.interval_unit,
            "run_time": self.run_time or "",
            "weekdays": self.weekdays or [],
            "auto_report": self.auto_report,
            "last_run_at": self.last_run_at.isoformat() if self.last_run_at else None,
            "next_run_at": self.next_run_at.isoformat() if self.next_run_at else None,
            "run_count": self.run_count,
            "created_at": self.created_at.isoformat() if self.created_at else None,
            "updated_at": self.updated_at.isoformat() if self.updated_at else None,
        }

    def schedule_description(self) -> str:
        """
        生成人类可读的周期描述

        Returns:
            str: 周期描述，如「每 30 分钟」「每天 22:00」
        """
        unit_map = {"minutes": "分钟", "hours": "小时", "days": "天"}
        if self.schedule_type == "interval":
            unit = unit_map.get(self.interval_unit, self.interval_unit)
            return f"每 {self.interval_value} {unit}"
        if self.schedule_type == "daily":
            return f"每天 {self.run_time or '--:--'}"
        if self.schedule_type == "weekly":
            weekday_names = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
            names = [weekday_names[w] for w in (self.weekdays or []) if 0 <= w <= 6]
            if not names:
                return f"每周 {self.run_time or '--:--'}"
            return f"每周{','.join(names)} {self.run_time or '--:--'}"
        return self.schedule_type
