from __future__ import annotations

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

from app.core.logging import get_logger
from app.db.session import get_session_factory
from app.services.finance_dashboard_snapshot import FinanceDashboardSnapshotService
from app.services.tenant_registry import DEFAULT_TENANT_ID

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


class FinanceDashboardScheduler:
    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_FINANCE_DASHBOARD_INTERVAL_SECONDS") or "120")
        initial_delay = int(
            os.environ.get("X_FINANCIAL_FINANCE_DASHBOARD_INITIAL_DELAY_SECONDS") or "6"
        )
        self._timezone = ZoneInfo(timezone_name or "Asia/Shanghai")
        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="finance-dashboard-scheduler",
                daemon=True,
            )
            self._thread.start()
            logger.info(
                "Finance dashboard 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("Finance dashboard 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_snapshot()
            except Exception:  # pragma: no cover - scheduler best effort logging
                logger.exception("Scheduled finance dashboard snapshot failed")
            if self._stop_event.wait(self._interval_seconds):
                break

    def _refresh_snapshot(self) -> None:
        db = get_session_factory()()
        try:
            dashboard = FinanceDashboardSnapshotService(
                db,
                tenant_id=DEFAULT_TENANT_ID,
            ).refresh_default_snapshot()
            db.commit()
            totals = dashboard.totals or {}
            logger.info(
                "Finance dashboard snapshot generated at=%s count=%s amount=%s",
                datetime.now(self._timezone).isoformat(),
                totals.get("reimbursementCount"),
                totals.get("reimbursementAmount"),
            )
        except Exception:
            db.rollback()
            raise
        finally:
            db.close()


finance_dashboard_scheduler = FinanceDashboardScheduler()
