#!/usr/bin/env python3
from __future__ import annotations

import os
import subprocess
from pathlib import Path


ROOT = Path(__file__).resolve().parents[2]
VERIFIER = ROOT / "ops/runner/check-awoooi-non110-runner-readiness.sh"


def _write_fake_bin(path: Path, name: str, body: str) -> None:
    target = path / name
    target.write_text(body, encoding="utf-8")
    target.chmod(0o755)


def _write_runner_config(path: Path) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(
        """
runner:
  capacity: 1
  labels:
    - "awoooi-host:host"
    - "awoooi-ubuntu:docker://192.168.0.110:5000/awoooi/ci-runner:act-22.04"
""".strip()
        + "\n",
        encoding="utf-8",
    )


def _write_unit(
    path: Path,
    binary_path: Path,
    config_path: Path,
    registration_path: Path,
) -> None:
    path.write_text(
        f"""
[Unit]
ConditionPathExists={registration_path}

[Service]
ExecStart={binary_path} daemon --config {config_path}
Restart=always
CPUQuota=200%
MemoryMax=8G
TasksMax=512
NoNewPrivileges=true
""".strip()
        + "\n",
        encoding="utf-8",
    )


def _write_path_unit(path: Path, registration_path: Path) -> None:
    path.write_text(
        f"""
[Unit]
Description=Watch AWOOOI non-110 runner registration metadata

[Path]
PathExists={registration_path}
Unit=awoooi-non110-runner-autostart.service

[Install]
WantedBy=default.target
""".strip()
        + "\n",
        encoding="utf-8",
    )


def _write_keepalive_timer(path: Path) -> None:
    path.write_text(
        """
[Unit]
Description=Periodically verify AWOOOI non-110 runner user service is active

[Timer]
OnBootSec=30s
OnUnitInactiveSec=60s
AccuracySec=10s
Unit=awoooi-non110-runner-keepalive.service

[Install]
WantedBy=timers.target
""".strip()
        + "\n",
        encoding="utf-8",
    )


def _write_keepalive_service(path: Path) -> None:
    path.write_text(
        """
[Unit]
Description=Keep AWOOOI non-110 runner active while enable sentinel exists

[Service]
Type=oneshot
ExecStart=/usr/bin/systemctl --user daemon-reload
ExecStart=-/usr/bin/systemctl --user reset-failed awoooi-non110-runner.service
ExecStart=/usr/bin/systemctl --user enable awoooi-non110-runner.service
ExecStart=/usr/bin/systemctl --user start awoooi-non110-runner.service
RemainAfterExit=no
""".strip()
        + "\n",
        encoding="utf-8",
    )


def _run_verifier(
    tmp_path: Path,
    registration_path: Path,
    *,
    active_service: bool = True,
    unit_target_matches: bool = True,
    unmanaged_runner_container: bool = False,
    keepalive_timer: bool = True,
    keepalive_service_failed: bool = False,
) -> subprocess.CompletedProcess[str]:
    fake_bin = tmp_path / "bin"
    unit_dir = tmp_path / "units"
    fake_bin.mkdir()
    unit_dir.mkdir()
    _write_fake_bin(
        fake_bin,
        "systemctl",
        f"""#!/usr/bin/env bash
set -euo pipefail
if [ "${{1:-}}" = "--user" ]; then shift; fi
cmd="${{1:-}}"; unit="${{2:-}}"
case "$cmd" in
  show)
    if [ "${{2:-}}" = "-p" ]; then
      unit="${{1:-}}"
    fi
    if [ -f "{unit_dir}/$unit" ]; then
      if [[ "$unit" == *.path ]]; then
        printf 'LoadState=loaded\\nActiveState=active\\nUnitFileState=enabled\\nMainPID=0\\n'
        exit 0
      fi
      if [[ "$unit" == *.timer ]]; then
        printf 'LoadState=loaded\\nActiveState=active\\nUnitFileState=enabled\\nMainPID=0\\n'
        exit 0
      fi
      if [[ "$unit" == *keepalive.service ]]; then
        printf 'LoadState=loaded\\nActiveState={"failed" if keepalive_service_failed else "inactive"}\\nUnitFileState=static\\nMainPID=0\\nResult={"exit-code" if keepalive_service_failed else "success"}\\nExecMainStatus={"1" if keepalive_service_failed else "0"}\\n'
        exit 0
      fi
      printf 'LoadState=loaded\\nActiveState={"active" if active_service else "inactive"}\\nUnitFileState=disabled\\nMainPID={"1234" if active_service else "0"}\\n'
      exit 0
    fi
    if [ "${{2:-}}" = "-p" ] && [ "${{3:-}}" = "LoadState" ]; then
      printf 'not-found\\n'
      exit 0
    fi
    printf 'LoadState=not-found\\nActiveState=inactive\\nUnitFileState=\\nMainPID=0\\n'
    exit 0
    ;;
  cat)
    if [ -f "{unit_dir}/$unit" ]; then cat "{unit_dir}/$unit"; exit 0; fi
    exit 1
    ;;
esac
exit 1
""",
    )
    unmanaged_runner_output = (
        "printf 'condescending_wilbur|gitea/act_runner:latest\\n'"
        if unmanaged_runner_container
        else "exit 0"
    )
    _write_fake_bin(
        fake_bin,
        "docker",
        f"""#!/usr/bin/env bash
if [ "${{1:-}}" = "ps" ]; then
  if printf '%s\\n' "$*" | grep -q 'Image'; then
    {unmanaged_runner_output}
    exit 0
  fi
  exit 0
fi
exit 0
""",
    )
    _write_fake_bin(
        fake_bin,
        "pgrep",
        """#!/usr/bin/env bash
exit 1
""",
    )
    _write_fake_bin(
        fake_bin,
        "ip",
        """#!/usr/bin/env bash
if [ "${1:-}" = "-o" ] && [ "${2:-}" = "-4" ] && [ "${3:-}" = "addr" ]; then
  printf '1: lo    inet 127.0.0.1/8 scope host lo\\n'
  printf '2: eth0  inet 192.168.0.188/24 brd 192.168.0.255 scope global eth0\\n'
  exit 0
fi
exit 1
""",
    )

    config_path = tmp_path / "config.yaml"
    binary_path = tmp_path / "act_runner"
    _write_runner_config(config_path)
    binary_path.write_text("#!/usr/bin/env bash\nexit 0\n", encoding="utf-8")
    binary_path.chmod(0o755)
    unit_binary_path = binary_path if unit_target_matches else tmp_path / "other_act_runner"
    unit_config_path = config_path if unit_target_matches else tmp_path / "other_config.yaml"
    _write_unit(
        unit_dir / "awoooi-non110-runner.service",
        unit_binary_path,
        unit_config_path,
        registration_path,
    )
    _write_unit(
        unit_dir / "awoooi-non110-runner-rollback.service",
        unit_binary_path,
        unit_config_path,
        registration_path,
    )
    _write_path_unit(
        unit_dir / "awoooi-non110-runner-autostart.path",
        registration_path,
    )
    if keepalive_timer:
        _write_keepalive_service(unit_dir / "awoooi-non110-runner-keepalive.service")
        _write_keepalive_timer(unit_dir / "awoooi-non110-runner-keepalive.timer")

    env = {
        **os.environ,
        "PATH": f"{fake_bin}:{os.environ['PATH']}",
        "TARGET_HOST_IP": "",
        "FORBIDDEN_HOST_IPS": "",
        "RUNNER_CONFIG_PATHS": str(config_path),
        "RUNNER_BINARY_PATHS": str(binary_path),
        "RUNNER_SERVICE_NAMES": "awoooi-non110-runner.service",
        "RUNNER_AUTOSTART_PATH_UNIT_NAMES": "awoooi-non110-runner-autostart.path",
        "RUNNER_KEEPALIVE_SERVICE_UNIT_NAMES": "awoooi-non110-runner-keepalive.service",
        "RUNNER_KEEPALIVE_TIMER_UNIT_NAMES": "awoooi-non110-runner-keepalive.timer",
        "ROLLBACK_UNIT_NAMES": "awoooi-non110-runner-rollback.service",
        "RUNNER_REGISTRATION_PATHS": str(registration_path),
        "MAX_HEAVY_PROCESS_COUNT": "0",
    }
    return subprocess.run(
        ["bash", str(VERIFIER)],
        check=False,
        env=env,
        text=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
    )


def test_non110_readiness_blocks_without_registration_state(tmp_path: Path) -> None:
    result = _run_verifier(tmp_path, tmp_path / ".runner")
    assert result.returncode == 1
    assert "BLOCKER runner_registration_missing" in result.stdout
    assert "AWOOOI_NON110_RUNNER_READY=0" in result.stdout
    assert "raw_runner_registration_read=false" in result.stdout
    assert (
        "safe_next_step=run_register_awoooi_non110_runner_script_without_printing_token_then_autostart_path_will_enable_service_and_rerun_this_verifier"
        in result.stdout
    )
    assert "RUNNER_AUTOSTART_PATH unit=awoooi-non110-runner-autostart.path installed=1" in result.stdout
    assert (
        "RUNNER_AUTOSTART_PATH_WATCH unit=awoooi-non110-runner-autostart.path registration_watch=1 active=1 enabled=1"
        in result.stdout
    )
    assert "READY_AUTOSTART_PATH_COUNT=1" in result.stdout
    assert "RUNNER_KEEPALIVE_TIMER unit=awoooi-non110-runner-keepalive.timer installed=1" in result.stdout
    assert "BLOCKER runner_keepalive_timer_not_ready" not in result.stdout
    assert "BLOCKER runner_keepalive_service_not_ready" not in result.stdout


def test_non110_readiness_accepts_registration_state_presence_without_reading_it(
    tmp_path: Path,
) -> None:
    registration_path = tmp_path / ".runner"
    registration_path.write_text("secret-token-like-content-not-printed\n", encoding="utf-8")
    result = _run_verifier(tmp_path, registration_path)
    assert result.returncode == 0, result.stdout + result.stderr
    assert "RUNNER_REGISTRATION" in result.stdout
    assert "present=1" in result.stdout
    assert "content_read=false" in result.stdout
    assert "registration_condition=1" in result.stdout
    assert "RUNNER_KEEPALIVE_SERVICE unit=awoooi-non110-runner-keepalive.service installed=1" in result.stdout
    assert "READY_KEEPALIVE_SERVICE_COUNT=1" in result.stdout
    assert "RUNNER_KEEPALIVE_TIMER unit=awoooi-non110-runner-keepalive.timer installed=1" in result.stdout
    assert "READY_KEEPALIVE_TIMER_COUNT=1" in result.stdout
    assert "secret-token-like-content" not in result.stdout
    assert "AWOOOI_NON110_RUNNER_READY=1" in result.stdout


def test_non110_readiness_blocks_failed_keepalive_service(tmp_path: Path) -> None:
    registration_path = tmp_path / ".runner"
    registration_path.write_text("secret-token-like-content-not-printed\n", encoding="utf-8")
    result = _run_verifier(
        tmp_path,
        registration_path,
        keepalive_service_failed=True,
    )
    assert result.returncode == 1
    assert "BLOCKER runner_keepalive_service_failed:awoooi-non110-runner-keepalive.service" in result.stdout
    assert "BLOCKER runner_keepalive_service_not_ready" in result.stdout
    assert "secret-token-like-content" not in result.stdout
    assert "AWOOOI_NON110_RUNNER_READY=0" in result.stdout


def test_non110_readiness_blocks_registered_runner_without_keepalive_timer(
    tmp_path: Path,
) -> None:
    registration_path = tmp_path / ".runner"
    registration_path.write_text("secret-token-like-content-not-printed\n", encoding="utf-8")
    result = _run_verifier(tmp_path, registration_path, keepalive_timer=False)
    assert result.returncode == 1
    assert "BLOCKER runner_keepalive_timer_not_ready" in result.stdout
    assert "READY_KEEPALIVE_TIMER_COUNT=0" in result.stdout
    assert "secret-token-like-content" not in result.stdout
    assert "AWOOOI_NON110_RUNNER_READY=0" in result.stdout


def test_non110_readiness_blocks_service_target_mismatch(tmp_path: Path) -> None:
    registration_path = tmp_path / ".runner"
    registration_path.write_text("secret-token-like-content-not-printed\n", encoding="utf-8")
    result = _run_verifier(tmp_path, registration_path, unit_target_matches=False)
    assert result.returncode == 1
    assert "BLOCKER runner_service_target_mismatch:awoooi-non110-runner.service" in result.stdout
    assert "RUNNER_SERVICE_TARGETS unit=awoooi-non110-runner.service" in result.stdout
    assert "AWOOOI_NON110_RUNNER_READY=0" in result.stdout


def test_non110_readiness_blocks_unmanaged_act_runner_container(tmp_path: Path) -> None:
    registration_path = tmp_path / ".runner"
    registration_path.write_text("secret-token-like-content-not-printed\n", encoding="utf-8")
    result = _run_verifier(
        tmp_path,
        registration_path,
        unmanaged_runner_container=True,
    )
    assert result.returncode == 1
    assert "UNMANAGED_RUNNER_CONTAINERS=condescending_wilbur" in result.stdout
    assert (
        "BLOCKER unmanaged_runner_containers_present:condescending_wilbur"
        in result.stdout
    )
    assert "secret-token-like-content" not in result.stdout
