"""Windows service backend using pywin32.

Only imported on Windows — guarded by the dispatcher in ``konstant.service``.
"""

from __future__ import annotations

import sys
from pathlib import Path
from typing import Optional

import servicemanager  # type: ignore[import-untyped]
import win32event  # type: ignore[import-untyped]
import win32service  # type: ignore[import-untyped]
import win32serviceutil  # type: ignore[import-untyped]

from konstant.config import KonstantConfig, ServiceConfig
from konstant.process import ProcessManager


_SERVICE_PREFIX = "konstant_"


def _win_service_name(service_name: str) -> str:
    return f"{_SERVICE_PREFIX}{service_name}"


def _win_display_name(service_name: str) -> str:
    return f"konstant — {service_name}"


# ------------------------------------------------------------------
# Service class
# ------------------------------------------------------------------


class KonstantWinService(win32serviceutil.ServiceFramework):
    """Thin Windows service that delegates to ProcessManager."""

    _svc_name_ = "konstant_generic"
    _svc_display_name_ = "konstant — generic"
    _svc_description_ = "Managed by konstant process manager"

    _config_path: str = ""
    _service_key: str = ""

    def __init__(self, args: list[str]) -> None:
        super().__init__(args)
        self.stop_event = win32event.CreateEvent(None, 0, 0, None)
        self.manager: ProcessManager | None = None

    def SvcStop(self) -> None:
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.stop_event)
        if self.manager is not None:
            self.manager.stop()

    def SvcDoRun(self) -> None:
        servicemanager.LogMsg(
            servicemanager.EVENTLOG_INFORMATION_TYPE,
            servicemanager.PYS_SERVICE_STARTED,
            (self._svc_name_, ""),
        )
        try:
            self._run()
        except Exception as exc:
            servicemanager.LogErrorMsg(f"konstant service error: {exc}")

    def _run(self) -> None:
        config_path = Path(self._config_path) if self._config_path else None
        cfg = KonstantConfig.load(config_path)
        svc_cfg = cfg.get_service(self._service_key)
        self.manager = ProcessManager(svc_cfg)
        self.manager.start()

        while True:
            rc = win32event.WaitForSingleObject(self.stop_event, 5000)
            if rc == win32event.WAIT_OBJECT_0:
                break
        if self.manager is not None:
            self.manager.stop()


# ------------------------------------------------------------------
# Install / uninstall
# ------------------------------------------------------------------


def install_service(
    config: ServiceConfig,
    user: Optional[str] = None,
    password: Optional[str] = None,
    config_path: Optional[Path] = None,
) -> None:
    """Register a konstant-managed process as a Windows service."""
    svc_name = _win_service_name(config.name)
    display = _win_display_name(config.name)

    cls_name = f"KonstantWinService_{config.name}"
    svc_cls = type(
        cls_name,
        (KonstantWinService,),
        {
            "_svc_name_": svc_name,
            "_svc_display_name_": display,
            "_service_key": config.name,
            "_config_path": str(config_path or ""),
        },
    )

    win32serviceutil.InstallService(
        pythonClassString=f"{svc_cls.__module__}.{cls_name}",
        serviceName=svc_name,
        displayName=display,
        startType=win32service.SERVICE_AUTO_START,
        userName=user,
        password=password,
        description=f"konstant-managed service: {config.name}",
    )


def uninstall_service(service_name: str) -> None:
    """Remove a konstant Windows service registration."""
    svc_name = _win_service_name(service_name)
    win32serviceutil.RemoveService(svc_name)
