#!/usr/bin/env python3
"""Keep N analytics RabbitMQ workers running (shared analytics_jobs queue)."""

from __future__ import annotations

import logging
import os
import subprocess
import sys
import time

from dotenv import load_dotenv

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
load_dotenv(os.path.join(BASE_DIR, ".env"))

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s",
)
logger = logging.getLogger("analytics_worker_supervisor")

ANALYTICS_WORKER_COUNT = max(1, int(os.getenv("ANALYTICS_WORKER_COUNT", "2")))
SUPERVISOR_INTERVAL_SEC = max(10, int(os.getenv("ANALYTICS_SUPERVISOR_INTERVAL_SEC", "60")))
WORKER_MATCH = os.path.join(BASE_DIR, "analytics_worker.py")


def worker_python() -> str:
    venv_py = os.path.join(BASE_DIR, "venv", "bin", "python")
    return venv_py if os.path.isfile(venv_py) else "python3"


def list_worker_pids() -> list[int]:
    try:
        result = subprocess.run(
            ["pgrep", "-f", WORKER_MATCH],
            capture_output=True,
            text=True,
            timeout=10,
        )
        if result.returncode == 0:
            return sorted(int(x) for x in result.stdout.split() if x.strip().isdigit())
    except Exception:
        pass
    return []


def start_worker() -> None:
    py = worker_python()
    log_path = "/tmp/analytics_worker.log"
    subprocess.Popen(
        ["bash", "-lc", f'nohup "{py}" "{WORKER_MATCH}" >>"{log_path}" 2>&1 &'],
        cwd=BASE_DIR,
    )


def sync_workers() -> dict:
    target = ANALYTICS_WORKER_COUNT
    running = list_worker_pids()
    started = 0
    while len(running) + started < target:
        start_worker()
        started += 1
        time.sleep(0.5)
    running_after = len(list_worker_pids())
    return {
        "target_workers": target,
        "running_after": running_after,
        "started": started,
        "queue": os.getenv("RABBITMQ_ANALYTICS_QUEUE", "analytics_jobs"),
    }


def main() -> None:
    once = "--once" in sys.argv
    logger.info(
        "Analytics worker supervisor (%s); target=%s workers",
        "once" if once else f"every {SUPERVISOR_INTERVAL_SEC}s",
        ANALYTICS_WORKER_COUNT,
    )
    while True:
        try:
            summary = sync_workers()
            logger.info(
                "Analytics workers: %s/%s running (started %s this pass)",
                summary.get("running_after"),
                summary.get("target_workers"),
                summary.get("started"),
            )
        except Exception as exc:
            logger.exception("Analytics supervisor sync failed: %s", exc)
        if once:
            break
        time.sleep(SUPERVISOR_INTERVAL_SEC)


if __name__ == "__main__":
    main()
