from __future__ import annotations

import os
import threading

from app.core.logging import get_logger
from app.db.session import get_session_factory
from app.services.approval_task_sla import ApprovalTaskSlaService

logger = get_logger("app.services.approval_task_scheduler")


class ApprovalTaskScheduler:
    def __init__(self) -> None:
        interval = int(os.environ.get("X_FINANCIAL_APPROVAL_TASK_INTERVAL_SECONDS") or "60")
        initial_delay = int(
            os.environ.get("X_FINANCIAL_APPROVAL_TASK_INITIAL_DELAY_SECONDS") or "10"
        )
        self._interval_seconds = max(30, interval)
        self._initial_delay_seconds = max(1, initial_delay)
        self._stop_event = threading.Event()
        self._thread: threading.Thread | None = None
        self._lock = threading.Lock()

    def start(self) -> None:
        with self._lock:
            if self._thread is not None and self._thread.is_alive():
                return
            self._stop_event.clear()
            self._thread = threading.Thread(
                target=self._run_loop,
                name="approval-task-scheduler",
                daemon=True,
            )
            self._thread.start()
        logger.info(
            "Approval task scheduler started interval=%ss",
            self._interval_seconds,
        )

    def shutdown(self) -> None:
        with self._lock:
            thread = self._thread
            self._thread = None
        self._stop_event.set()
        if thread is not None and thread.is_alive():
            thread.join(timeout=3)
        logger.info("Approval task scheduler stopped")

    def _run_loop(self) -> None:
        if self._stop_event.wait(self._initial_delay_seconds):
            return
        while not self._stop_event.is_set():
            try:
                self._run_once()
            except Exception:  # pragma: no cover - scheduler best effort logging
                logger.exception("Scheduled approval task SLA escalation failed")
            if self._stop_event.wait(self._interval_seconds):
                break

    @staticmethod
    def _run_once() -> None:
        db = get_session_factory()()
        try:
            escalated = ApprovalTaskSlaService(db).escalate_due_tasks()
            db.commit()
            if escalated:
                logger.info("Approval task SLA escalated count=%s", len(escalated))
        except Exception:
            db.rollback()
            raise
        finally:
            db.close()


approval_task_scheduler = ApprovalTaskScheduler()
