"""定时任务执行记录写入辅助。"""
from __future__ import annotations

import json
import logging
import uuid
from datetime import datetime
from typing import Any

from supply_infra.db.repositories.scheduler_job_execution_repo import (
    SchedulerJobExecutionRepository,
)
from supply_infra.db.session import get_session

logger = logging.getLogger(__name__)

STATUS_STARTED = "started"
STATUS_FINISHED = "finished"
STATUS_FAILED = "failed"
STATUS_SKIPPED = "skipped"


def _serialize_detail(payload: Any) -> str | None:
    if payload is None:
        return None
    return json.dumps(payload, ensure_ascii=False, default=str)


class JobExecutionRecorder:
    """在任务开始/结束时各写一条执行记录。"""

    def __init__(
        self,
        *,
        job_name: str,
        job_id: str | None = None,
        biz_dt: str | None = None,
    ) -> None:
        self.run_id = str(uuid.uuid4())
        self.job_name = job_name
        self.job_id = job_id
        self.biz_dt = biz_dt
        self.started_at = datetime.now()

    def record_started(self) -> None:
        try:
            with get_session() as session:
                SchedulerJobExecutionRepository(session).log_event(
                    run_id=self.run_id,
                    job_name=self.job_name,
                    job_id=self.job_id,
                    status=STATUS_STARTED,
                    event_time=self.started_at,
                    biz_dt=self.biz_dt,
                    started_at=self.started_at,
                )
        except Exception:
            logger.exception("Failed to record job start: job_name=%s run_id=%s", self.job_name, self.run_id)

    def record_finished(
        self,
        *,
        success: bool,
        result: dict[str, Any] | None = None,
        error_message: str | None = None,
    ) -> None:
        finished_at = datetime.now()
        duration_seconds = round((finished_at - self.started_at).total_seconds(), 2)
        status = STATUS_FINISHED if success else STATUS_FAILED

        try:
            with get_session() as session:
                SchedulerJobExecutionRepository(session).log_event(
                    run_id=self.run_id,
                    job_name=self.job_name,
                    job_id=self.job_id,
                    status=status,
                    event_time=finished_at,
                    biz_dt=self.biz_dt,
                    started_at=self.started_at,
                    finished_at=finished_at,
                    duration_seconds=duration_seconds,
                    error_message=error_message,
                    detail=_serialize_detail(result),
                )
        except Exception:
            logger.exception(
                "Failed to record job finish: job_name=%s run_id=%s status=%s",
                self.job_name,
                self.run_id,
                status,
            )


def record_skipped(
    *,
    job_name: str,
    job_id: str | None = None,
    biz_dt: str | None = None,
    reason: str,
) -> None:
    """记录因并发等原因跳过的执行。"""
    now = datetime.now()
    run_id = str(uuid.uuid4())
    try:
        with get_session() as session:
            SchedulerJobExecutionRepository(session).log_event(
                run_id=run_id,
                job_name=job_name,
                job_id=job_id,
                status=STATUS_SKIPPED,
                event_time=now,
                biz_dt=biz_dt,
                started_at=now,
                finished_at=now,
                duration_seconds=0,
                error_message=reason,
            )
    except Exception:
        logger.exception("Failed to record skipped job: job_name=%s reason=%s", job_name, reason)
