# retoor <retoor@molodetz.nl>

from __future__ import annotations

import subprocess
import sys

from devplacepy.config import XMLRPC_BIND, XMLRPC_PORT
from devplacepy.services.base import BaseService

XMLRPC_INTERVAL_SECONDS = 15
SERVER_MODULE = "devplacepy.services.xmlrpc.server"
TERMINATE_TIMEOUT_SECONDS = 10


class XmlrpcService(BaseService):
    title = "XML-RPC Bridge"
    description = (
        "Forking XML-RPC server that exposes every documented REST endpoint as an "
        "XML-RPC method. Reachable at /xmlrpc through the app and nginx."
    )
    default_enabled = True
    min_interval = 5

    def __init__(self) -> None:
        super().__init__("xmlrpc", interval_seconds=XMLRPC_INTERVAL_SECONDS)
        self._process: subprocess.Popen | None = None

    def _alive(self) -> bool:
        return self._process is not None and self._process.poll() is None

    def _spawn(self) -> None:
        self._process = subprocess.Popen(
            [sys.executable, "-m", SERVER_MODULE],
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
        )
        self.log(
            f"Forking XML-RPC server started (pid {self._process.pid}) on "
            f"{XMLRPC_BIND}:{XMLRPC_PORT}"
        )

    def _terminate(self) -> None:
        if not self._alive():
            self._process = None
            return
        self._process.terminate()
        try:
            self._process.wait(timeout=TERMINATE_TIMEOUT_SECONDS)
        except subprocess.TimeoutExpired:
            self._process.kill()
            self._process.wait()
        self.log("Forking XML-RPC server stopped")
        self._process = None

    async def on_enable(self) -> None:
        if not self._alive():
            self._spawn()

    async def on_disable(self) -> None:
        self._terminate()

    async def run_once(self) -> None:
        if self._alive():
            self.log(f"XML-RPC server healthy (pid {self._process.pid})")
            return
        self.log("XML-RPC server not running, starting it")
        self._spawn()

    def collect_metrics(self) -> dict:
        return {
            "running": self._alive(),
            "pid": self._process.pid if self._alive() else None,
            "bind": f"{XMLRPC_BIND}:{XMLRPC_PORT}",
        }


__all__ = ["XmlrpcService"]
