from __future__ import annotations

import os
import threading
from datetime import datetime
from zoneinfo import ZoneInfo

from sqlalchemy import select

from app.core.agent_enums import AgentRunSource
from app.core.logging import get_logger
from app.db.session import get_session_factory
from app.models.tenant import Tenant
from app.services.employee_profile_scan_task import EmployeeProfileScanTaskService

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


class EmployeeProfileScheduler:
    def __init__(self) -> None:
        timezone_name = str(os.environ.get("X_FINANCIAL_SCHEDULER_TZ") or "Asia/Shanghai").strip()
        interval = int(os.environ.get("X_FINANCIAL_EMPLOYEE_PROFILE_INTERVAL_SECONDS") or "1800")
        initial_delay = int(
            os.environ.get("X_FINANCIAL_EMPLOYEE_PROFILE_INITIAL_DELAY_SECONDS") or "18"
        )
        self._timezone = ZoneInfo(timezone_name or "Asia/Shanghai")
        self._interval_seconds = max(300, 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="employee-profile-scheduler",
                daemon=True,
            )
            self._thread.start()
            logger.info(
                "Employee profile scheduler started timezone=%s interval=%ss",
                self._timezone.key,
                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("Employee profile 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._refresh_profiles()
            except Exception:  # pragma: no cover - scheduler best effort logging
                logger.exception("Scheduled employee profile scan failed")
            if self._stop_event.wait(self._interval_seconds):
                break

    def _refresh_profiles(self) -> None:
        db = get_session_factory()()
        try:
            tenant_ids = list(
                db.scalars(select(Tenant.tenant_id).where(Tenant.status == "active")).all()
            )
            for tenant_id in tenant_ids:
                result = EmployeeProfileScanTaskService(db).refresh_profiles(
                    source=AgentRunSource.SCHEDULE.value,
                    tenant_id=tenant_id,
                )
                summary = result.get("summary") or {}
                logger.info(
                    "Employee profile scan generated tenant=%s at=%s "
                    "employees=%s snapshots=%s attention=%s",
                    tenant_id,
                    datetime.now(self._timezone).isoformat(),
                    summary.get("target_employee_count"),
                    summary.get("snapshot_count"),
                    summary.get("high_attention_employee_count"),
                )
        except Exception:
            db.rollback()
            raise
        finally:
            db.close()


employee_profile_scheduler = EmployeeProfileScheduler()
