#!/usr/bin/env python3
"""Patch Discord role env vars, deploy web code, rebuild and restart PM2."""
import sys
from pathlib import Path

import paramiko
from scp import SCPClient

sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from deploy_vps import (  # noqa: E402
    VPS_HOST,
    VPS_USER,
    VPS_PASS,
    REMOTE_DIR,
    parse_env_lines,
    upload_project,
)

ENV_ADD = {
    "DISCORD_GUILD_ID": "1355010522512359434",
    "DISCORD_LINKED_ROLE_ID": "1414835939603120151",
}


def run(client, cmd: str, timeout: int = 600) -> str:
    _, stdout, stderr = client.exec_command(cmd, timeout=timeout)
    return (stdout.read() + stderr.read()).decode("utf-8", errors="replace")


def patch_env(client) -> None:
    env_path = f"{REMOTE_DIR}/.env.production"
    current = run(client, f"cat {env_path} 2>/dev/null", timeout=15)
    values = parse_env_lines(current)
    changed = False
    for key, default in ENV_ADD.items():
        if not values.get(key):
            values[key] = default
            changed = True
    if not changed:
        print("  .env.production: role vars already set")
        return
    lines = current.splitlines()
    out: list[str] = []
    seen: set[str] = set()
    for line in lines:
        if "=" in line and not line.strip().startswith("#"):
            key = line.split("=", 1)[0].strip()
            if key in ENV_ADD:
                out.append(f"{key}={values[key]}")
                seen.add(key)
                continue
        out.append(line)
    for key in ENV_ADD:
        if key not in seen:
            out.append(f"{key}={values[key]}")
    content = "\n".join(out).rstrip() + "\n"
    with client.open_sftp().file(env_path, "w") as f:
        f.write(content)
    print("  .env.production: added DISCORD_GUILD_ID + DISCORD_LINKED_ROLE_ID")


def main() -> int:
    client = paramiko.SSHClient()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    print(f"Connecting to {VPS_HOST}...")
    client.connect(VPS_HOST, username=VPS_USER, password=VPS_PASS, timeout=20)

    print("Patching env...")
    patch_env(client)

    print("Uploading code...")
    with SCPClient(client.get_transport()) as scp:
        upload_project(scp, client)

    print("Building...")
    out = run(client, f"cd {REMOTE_DIR} && npm run build 2>&1 | tail -8", timeout=600)
    sys.stdout.buffer.write(out.encode("utf-8", errors="replace"))

    print("Restarting PM2...")
    run(
        client,
        f"cd {REMOTE_DIR} && pm2 restart urbangamers backup-pinger --update-env && pm2 save",
        timeout=60,
    )

    verify = run(client, f"grep DISCORD_LINKED_ROLE_ID {REMOTE_DIR}/.env.production", timeout=10)
    print(verify.strip())
    client.close()
    print("Deploy complete.")
    return 0


if __name__ == "__main__":
    sys.exit(main())
