"""JobService 服务层 — Phase 8 任务 2.10.

将 JobService 与 VideoComposeService 集成，提供视频合成的完整异步工作流：
1. 创建 Job（记录任务元数据）
2. 提交执行（dispatch Celery 任务）
3. Celery 任务中更新进度、处理完成/失败

同时也提供通用的 Job 管理能力，供 ClipPlanService、RenderOrchestrator 等使用。
"""

from __future__ import annotations

import logging
from typing import Any

from sqlalchemy.orm import Session

from packages.application.jobs import (
    CancelJobUseCase,
    CompleteJobCommand,
    CompleteJobUseCase,
    CreateJobCommand,
    CreateJobUseCase,
    FailJobCommand,
    FailJobUseCase,
    GetJobStatisticsUseCase,
    GetJobUseCase,
    ListJobsUseCase,
    RetryJobUseCase,
    SubmitJobUseCase,
    UpdateJobProgressCommand,
    UpdateJobProgressUseCase,
)
from packages.domain.job import Job, JobStatus, JobType
from packages.ports.job_repository import JobRepository

logger = logging.getLogger(__name__)


class JobService:
    """统一异步任务管理服务。

    职责：
    - 为视频合成等耗时操作提供统一的异步任务管理
    - 封装 Use Case 的调用，提供简洁的服务接口
    - 与 VideoComposeService 集成，支持视频合成工作流

    用法::

        job_service = JobService(db)
        job = job_service.create_compose_job(
            project_id="xxx",
            plan_id="yyy",
            user_id="zzz",
        )
        job_service.submit_job(job.id, celery_task_id="celery-xxx")
    """

    def __init__(self, job_repo: JobRepository):
        self._job_repo = job_repo

    # ── 创建任务 ──────────────────────────────────────────────────────────

    def create_compose_job(
        self,
        project_id: str,
        plan_id: str,
        user_id: str,
        *,
        max_retries: int = 3,
    ) -> Job:
        """创建视频合成任务。

        Args:
            project_id: 项目 ID
            plan_id: EditPlan ID
            user_id: 创建人 ID
            max_retries: 最大重试次数

        Returns:
            创建的 Job 实例
        """
        use_case = CreateJobUseCase(self._job_repo)
        return use_case.execute(
            CreateJobCommand(
                project_id=project_id,
                job_type=JobType.VIDEO_COMPOSE,
                payload={"plan_id": plan_id},
                source_id=plan_id,
                created_by_user_id=user_id,
                max_retries=max_retries,
            )
        )

    def create_render_job(
        self,
        project_id: str,
        plan_id: str,
        user_id: str,
        *,
        max_retries: int = 3,
    ) -> Job:
        """创建剪辑计划渲染任务。"""
        use_case = CreateJobUseCase(self._job_repo)
        return use_case.execute(
            CreateJobCommand(
                project_id=project_id,
                job_type=JobType.RENDER_EDIT_PLAN,
                payload={"plan_id": plan_id},
                source_id=plan_id,
                created_by_user_id=user_id,
                max_retries=max_retries,
            )
        )

    def create_job(
        self,
        project_id: str,
        job_type: JobType | str,
        *,
        payload: dict | None = None,
        source_id: str = "",
        user_id: str = "",
        max_retries: int = 3,
    ) -> Job:
        """创建通用任务。"""
        use_case = CreateJobUseCase(self._job_repo)
        return use_case.execute(
            CreateJobCommand(
                project_id=project_id,
                job_type=job_type,
                payload=payload or {},
                source_id=source_id,
                created_by_user_id=user_id,
                max_retries=max_retries,
            )
        )

    # ── 提交执行 ──────────────────────────────────────────────────────────

    def submit_job(self, job_id: str, celery_task_id: str = "") -> Job:
        """提交任务执行。"""
        use_case = SubmitJobUseCase(self._job_repo)
        return use_case.execute(job_id, celery_task_id)

    # ── 进度更新 ──────────────────────────────────────────────────────────

    def update_progress(self, job_id: str, progress: float, stage: str = "") -> Job:
        """更新任务进度。"""
        use_case = UpdateJobProgressUseCase(self._job_repo)
        return use_case.execute(
            UpdateJobProgressCommand(
                job_id=job_id,
                progress=progress,
                current_stage=stage,
            )
        )

    # ── 完成 / 失败 ────────────────────────────────────────────────────────

    def complete_job(self, job_id: str, result: dict | None = None) -> Job:
        """标记任务完成。"""
        use_case = CompleteJobUseCase(self._job_repo)
        return use_case.execute(CompleteJobCommand(job_id=job_id, result=result or {}))

    def fail_job(self, job_id: str, error_message: str) -> Job:
        """标记任务失败。"""
        use_case = FailJobUseCase(self._job_repo)
        return use_case.execute(FailJobCommand(job_id=job_id, error_message=error_message))

    # ── 重试 / 取消 ────────────────────────────────────────────────────────

    def retry_job(self, job_id: str) -> Job:
        """重试失败任务。"""
        use_case = RetryJobUseCase(self._job_repo)
        return use_case.execute(job_id)

    def cancel_job(self, job_id: str) -> Job:
        """取消任务。"""
        use_case = CancelJobUseCase(self._job_repo)
        return use_case.execute(job_id)

    # ── 查询 ─────────────────────────────────────────────────────────────

    def get_job(self, job_id: str) -> Job | None:
        """获取任务详情。"""
        use_case = GetJobUseCase(self._job_repo)
        return use_case.execute(job_id)

    def list_project_jobs(
        self,
        project_id: str,
        *,
        job_type: JobType | str | None = None,
        status: JobStatus | str | None = None,
        limit: int = 50,
        offset: int = 0,
    ) -> list[Job]:
        """获取项目下的任务列表。"""
        use_case = ListJobsUseCase(self._job_repo)
        return use_case.execute(
            project_id=project_id,
            job_type=job_type,
            status=status,
            limit=limit,
            offset=offset,
        )

    def list_user_jobs(
        self,
        user_id: str,
        *,
        job_type: JobType | str | None = None,
        status: JobStatus | str | None = None,
        limit: int = 50,
        offset: int = 0,
    ) -> list[Job]:
        """获取用户的任务列表。"""
        use_case = ListJobsUseCase(self._job_repo)
        return use_case.execute(
            user_id=user_id,
            job_type=job_type,
            status=status,
            limit=limit,
            offset=offset,
        )

    def get_statistics(self, project_id: str) -> dict[str, Any]:
        """获取项目任务统计。"""
        use_case = GetJobStatisticsUseCase(self._job_repo)
        return use_case.execute(project_id)

    # ── 防重复检查 ────────────────────────────────────────────────────────

    def has_active_job_for_source(self, source_id: str, job_type: JobType | str) -> bool:
        """检查是否已有活跃任务（防止重复提交）。

        Args:
            source_id: 关联的业务实体 ID
            job_type: 任务类型

        Returns:
            True 如果存在活跃任务
        """
        return self._job_repo.find_active_by_source(source_id, job_type) is not None

    # ── 便捷方法：带防重的视频合成提交 ──────────────────────────────────────

    def submit_compose_if_not_exists(
        self,
        project_id: str,
        plan_id: str,
        user_id: str,
        celery_task_id: str = "",
    ) -> tuple[Job, bool]:
        """创建并提交视频合成任务（防重复）。

        Returns:
            (job, created): job 实例和是否新创建的标志
        """
        if self.has_active_job_for_source(plan_id, JobType.VIDEO_COMPOSE):
            existing = self._job_repo.find_active_by_source(plan_id, JobType.VIDEO_COMPOSE)
            logger.info("已存在活跃的视频合成任务: job_id=%s plan_id=%s", existing.id, plan_id)
            return existing, False

        job = self.create_compose_job(project_id, plan_id, user_id)
        job = self.submit_job(job.id, celery_task_id)
        return job, True
