import argparse
import posixpath
import shlex
import sys
from pathlib import Path

import paramiko


def parse_args():
    parser = argparse.ArgumentParser(description="Upload backend war to NAS and restart TongWeb.")
    parser.add_argument("--host", required=True)
    parser.add_argument("--port", type=int, required=True)
    parser.add_argument("--username", required=True)
    parser.add_argument("--password", required=True)
    parser.add_argument("--local-war", required=True)
    parser.add_argument("--remote-root", required=True)
    parser.add_argument("--tongweb-home", required=True)
    parser.add_argument("--app-name", required=True)
    return parser.parse_args()


def run_command(ssh, command):
    stdin, stdout, stderr = ssh.exec_command(command)
    exit_code = stdout.channel.recv_exit_status()
    output = stdout.read().decode("utf-8", errors="ignore")
    error = stderr.read().decode("utf-8", errors="ignore")
    return exit_code, output, error


def sudo_prefix(password):
    return f"printf '%s\\n' {shlex.quote(password)} | sudo -S -p '' "


def detect_command_prefix(ssh, password, command):
    plain_exit_code, _, _ = run_command(ssh, f"{command} >/dev/null 2>&1")
    if plain_exit_code == 0:
        return ""

    sudo_probe = f"{sudo_prefix(password)}{command} >/dev/null 2>&1"
    sudo_exit_code, _, _ = run_command(ssh, sudo_probe)
    if sudo_exit_code == 0:
        return sudo_prefix(password)

    raise RuntimeError(f"Remote command is not accessible: {command}")


def ensure_remote_path(ssh, prefix, remote_path):
    command = f"{prefix}mkdir -p {shlex.quote(remote_path)}"
    exit_code, output, error = run_command(ssh, command)
    if exit_code != 0:
        raise RuntimeError(f"Failed to create remote directory {remote_path}:\n{output}\n{error}")


def upload_file(sftp, local_file, remote_file):
    parent_dir = posixpath.dirname(remote_file)
    try:
        sftp.listdir(parent_dir)
    except OSError:
        raise RuntimeError(f"SFTP remote directory not found: {parent_dir}")
    sftp.put(str(local_file), remote_file)


def build_deploy_command(args, prefix):
    app_war_name = f"{args.app_name}.war"
    remote_war_path = posixpath.join(args.remote_root.rstrip("/"), "backend", app_war_name)
    autodeploy_dir = posixpath.join(args.tongweb_home.rstrip("/"), "autodeploy")
    deployed_war_path = posixpath.join(autodeploy_dir, app_war_name)
    deployed_dir_path = posixpath.join(autodeploy_dir, args.app_name)
    stop_script = posixpath.join(args.tongweb_home.rstrip("/"), "bin", "stopserver.sh")
    start_script = posixpath.join(args.tongweb_home.rstrip("/"), "bin", "startservernohup.sh")

    return (
        "set -e;"
        f"test -d {shlex.quote(args.tongweb_home)};"
        f"test -x {shlex.quote(stop_script)};"
        f"test -x {shlex.quote(start_script)};"
        f"{prefix}mkdir -p {shlex.quote(autodeploy_dir)};"
        f"{prefix}sh {shlex.quote(stop_script)} >/dev/null 2>&1 || true;"
        f"{prefix}rm -rf {shlex.quote(deployed_dir_path)};"
        f"{prefix}rm -f {shlex.quote(deployed_war_path)};"
        f"{prefix}cp {shlex.quote(remote_war_path)} {shlex.quote(deployed_war_path)};"
        f"{prefix}sh {shlex.quote(start_script)};"
        "sleep 5;"
        f"ls -l {shlex.quote(autodeploy_dir)};"
    )


def main():
    args = parse_args()
    local_war = Path(args.local_war).resolve()
    if not local_war.exists():
        raise FileNotFoundError(f"Local war does not exist: {local_war}")

    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(
        hostname=args.host,
        port=args.port,
        username=args.username,
        password=args.password,
        timeout=20,
    )

    sftp = ssh.open_sftp()
    try:
        remote_root = args.remote_root.rstrip("/")
        remote_backend_dir = posixpath.join(remote_root, "backend")
        remote_war_path = posixpath.join(remote_backend_dir, f"{args.app_name}.war")

        ensure_remote_path(ssh, "", remote_root)
        ensure_remote_path(ssh, "", remote_backend_dir)
        upload_file(sftp, local_war, remote_war_path)

        command_prefix = detect_command_prefix(ssh, args.password, f"test -d {shlex.quote(args.tongweb_home)}")
        deploy_command = build_deploy_command(args, command_prefix)
        exit_code, output, error = run_command(ssh, deploy_command)
        if exit_code != 0:
            raise RuntimeError(f"Remote TongWeb deploy failed:\n{output}\n{error}")

        print("=== DEPLOY OUTPUT ===")
        print(output.strip())
        if error.strip():
            print("=== DEPLOY STDERR ===")
            print(error.strip())
    finally:
        sftp.close()
        ssh.close()


if __name__ == "__main__":
    try:
        main()
    except Exception as exc:
        print(str(exc), file=sys.stderr)
        sys.exit(1)
