"""定时任务路由(DESIGN §8.5)。

前端只读展示 + 停用/删除两个便捷动作;建/改全走对话(schedule_* 工具)。
与对话工具共用 core.scheduler 服务层,两条路径不漂移。
"""
from __future__ import annotations

from uuid import UUID

from fastapi import Depends, HTTPException
from sqlalchemy import func, select

from core.storage import session_scope
from core.storage.models import Message, Task
from core.storage.usage_report import task_usage_aggregates as usage_aggregates

from ..common import task_dict
from ..schemas import SchedulePatchRequest


def register_schedule_routes(app, *, require_user) -> None:
    @app.get("/v1/schedules", tags=["schedules"])
    def list_schedules(user_id: UUID = Depends(require_user)):
        """列当前用户的定时任务(只读)。前端「定时」面板一次拉满。"""
        from core import scheduler
        return {"results": scheduler.list_jobs(user_id)}

    @app.patch("/v1/schedules/{job_id}", tags=["schedules"])
    def patch_schedule(
        job_id: str, body: SchedulePatchRequest, user_id: UUID = Depends(require_user),
    ):
        """改定时任务 —— 前端只用来停用/启用(enabled)。其余编辑走对话。"""
        from core import scheduler
        if body.enabled is None:
            raise HTTPException(400, "no fields to update")
        try:
            return scheduler.set_enabled(user_id, job_id, body.enabled)
        except scheduler.JobError as e:
            raise HTTPException(404, str(e))

    @app.delete("/v1/schedules/{job_id}", status_code=204, tags=["schedules"])
    def delete_schedule(job_id: str, user_id: UUID = Depends(require_user)):
        """删定时任务(软删,立即停止触发)。"""
        from core import scheduler
        try:
            scheduler.cancel_job(user_id, job_id)
        except scheduler.JobError as e:
            raise HTTPException(404, str(e))

    @app.get("/v1/schedules/{job_id}/tasks", tags=["schedules"])
    def list_schedule_tasks(
        job_id: str,
        page: int = 1,
        page_size: int = 20,
        user_id: UUID = Depends(require_user),
    ):
        """列某定时任务的历史执行 task(归属 scheduled_job_id),按 created_at 倒序分页。

        isolated 模式每次触发新建一个 task,这些 task 不进普通 /v1/tasks 列表
        (scheduled_job_id 过滤),只能经此端点回看;persistent 模式始终只有绑定的那一条。
        返回标准分页壳 `{page, page_size, count, results}`(results 同 /v1/tasks,复用 task_dict)。
        user_id 过滤天然隔离他人 job —— 非本人 / 非法 job_id 一律返回空列表。
        """
        page = max(1, page)
        page_size = max(1, min(page_size, 100))
        try:
            jid = UUID(str(job_id).strip())
        except (ValueError, AttributeError):
            return {"page": page, "page_size": page_size, "count": 0, "results": []}

        conditions = [
            Task.user_id == user_id,
            Task.deleted_at.is_(None),
            Task.scheduled_job_id == jid,
        ]
        offset = (page - 1) * page_size
        with session_scope() as s:
            cnt = s.execute(
                select(func.count()).select_from(Task).where(*conditions)
            ).scalar_one() or 0
            rows = s.execute(
                select(Task).where(*conditions)
                .order_by(Task.created_at.desc())
                .limit(page_size).offset(offset)
            ).scalars().all()
            tids = [r.task_id for r in rows]
            msg_counts: dict[UUID, int] = {}
            if tids:
                count_rows = s.execute(
                    select(Message.task_id, func.count())
                    .where(Message.task_id.in_(tids))
                    .group_by(Message.task_id)
                ).all()
                msg_counts = {
                    task_id: int(count) for task_id, count in count_rows
                }
            usage = usage_aggregates(s, tids)

        return {
            "page": page,
            "page_size": page_size,
            "count": int(cnt),
            "results": [
                task_dict(r, n_messages=msg_counts.get(r.task_id, 0), usage=usage.get(r.task_id))
                for r in rows
            ],
        }
