"""
System service registration for skop-runner.

Supports:
  - macOS: launchd (~/Library/LaunchAgents)
  - Linux: systemd user units (~/.config/systemd/user)
  - Windows: unsupported (prints manual instructions)
"""

import os
import shutil
import subprocess
import sys
from pathlib import Path

LABEL = "com.skoplabs.runner"
SERVICE_NAME = "skop-runner"


def get_skop_runner_path() -> str:
    """Find the installed skop-runner binary, resolving symlinks (pipx)."""
    path = shutil.which("skop-runner")
    if not path:
        raise FileNotFoundError(
            "Could not find 'skop-runner' on PATH. "
            "Make sure it is installed (pip install skop-runner)."
        )
    return str(Path(path).resolve())


# ============================================
# INSTALL
# ============================================


def install_service() -> str:
    """Install and start the system service. Returns a status message."""
    runner_path = get_skop_runner_path()

    if sys.platform == "darwin":
        return _install_macos(runner_path)
    elif sys.platform.startswith("linux"):
        return _install_linux(runner_path)
    else:
        raise RuntimeError(
            f"System service is not supported on {sys.platform}.\n"
            "You can run 'skop-runner start' manually or set up a scheduled task."
        )


def _install_macos(runner_path: str) -> str:
    plist_dir = Path.home() / "Library" / "LaunchAgents"
    plist_dir.mkdir(parents=True, exist_ok=True)
    plist_path = plist_dir / f"{LABEL}.plist"

    log_dir = Path.home() / "Library" / "Logs"
    log_dir.mkdir(parents=True, exist_ok=True)

    plist_content = f"""\
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>{LABEL}</string>
    <key>ProgramArguments</key>
    <array>
        <string>{runner_path}</string>
        <string>start</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>StandardOutPath</key>
    <string>{log_dir}/skop-runner.log</string>
    <key>StandardErrorPath</key>
    <string>{log_dir}/skop-runner.err</string>
</dict>
</plist>
"""
    # Unload first if already loaded (idempotent reinstall)
    if plist_path.exists():
        subprocess.run(
            ["launchctl", "unload", str(plist_path)],
            capture_output=True,
        )

    plist_path.write_text(plist_content)
    subprocess.run(
        ["launchctl", "load", str(plist_path)],
        check=True,
        capture_output=True,
    )
    return f"Service installed and started.\nLogs: {log_dir}/skop-runner.log"


def _install_linux(runner_path: str) -> str:
    unit_dir = Path.home() / ".config" / "systemd" / "user"
    unit_dir.mkdir(parents=True, exist_ok=True)
    unit_path = unit_dir / f"{SERVICE_NAME}.service"

    unit_content = f"""\
[Unit]
Description=Skop Runner
After=network-online.target
Wants=network-online.target

[Service]
ExecStart={runner_path} start
Restart=always
RestartSec=5
Environment=HOME={Path.home()}

[Install]
WantedBy=default.target
"""
    unit_path.write_text(unit_content)
    subprocess.run(
        ["systemctl", "--user", "daemon-reload"],
        check=True,
        capture_output=True,
    )
    subprocess.run(
        ["systemctl", "--user", "enable", "--now", SERVICE_NAME],
        check=True,
        capture_output=True,
    )
    return f"Service installed and started.\nLogs: journalctl --user -u {SERVICE_NAME} -f"


# ============================================
# UNINSTALL
# ============================================


def uninstall_service() -> str:
    """Stop and remove the system service. Returns a status message."""
    if sys.platform == "darwin":
        return _uninstall_macos()
    elif sys.platform.startswith("linux"):
        return _uninstall_linux()
    else:
        raise RuntimeError(f"System service is not supported on {sys.platform}.")


def _uninstall_macos() -> str:
    plist_path = Path.home() / "Library" / "LaunchAgents" / f"{LABEL}.plist"
    if not plist_path.exists():
        return "Service is not installed."

    subprocess.run(
        ["launchctl", "unload", str(plist_path)],
        capture_output=True,
    )
    plist_path.unlink()
    return "Service stopped and removed."


def _uninstall_linux() -> str:
    unit_path = (
        Path.home() / ".config" / "systemd" / "user" / f"{SERVICE_NAME}.service"
    )
    if not unit_path.exists():
        return "Service is not installed."

    subprocess.run(
        ["systemctl", "--user", "disable", "--now", SERVICE_NAME],
        capture_output=True,
    )
    unit_path.unlink()
    subprocess.run(
        ["systemctl", "--user", "daemon-reload"],
        capture_output=True,
    )
    return "Service stopped and removed."


# ============================================
# STATUS
# ============================================


def get_service_status() -> str:
    """Return service status: 'running', 'stopped', or 'not installed'."""
    if sys.platform == "darwin":
        return _status_macos()
    elif sys.platform.startswith("linux"):
        return _status_linux()
    else:
        return "not supported"


def _status_macos() -> str:
    plist_path = Path.home() / "Library" / "LaunchAgents" / f"{LABEL}.plist"
    if not plist_path.exists():
        return "not installed"

    result = subprocess.run(
        ["launchctl", "list", LABEL],
        capture_output=True,
        text=True,
    )
    if result.returncode != 0:
        return "stopped"

    # launchctl list <LABEL> returns a dict format.
    # If "PID" key is present, the process is running.
    if '"PID"' in result.stdout:
        return "running"
    return "stopped"


def _status_linux() -> str:
    unit_path = (
        Path.home() / ".config" / "systemd" / "user" / f"{SERVICE_NAME}.service"
    )
    if not unit_path.exists():
        return "not installed"

    result = subprocess.run(
        ["systemctl", "--user", "is-active", SERVICE_NAME],
        capture_output=True,
        text=True,
    )
    status = result.stdout.strip()
    if status == "active":
        return "running"
    return "stopped"
