import os
import sysconfig
import sys
from typing import cast
from zscams.agent.src.core.backend.client import backend_client
from zscams.agent.src.support.configuration import ROOT_PATH, config, CONFIG_PATH
from zscams.agent.src.support.logger import get_logger
from zscams.agent.src.support.os import (
    create_system_user,
    install_service,
    set_directory_ownership_and_permissions,
)
from zscams.agent.src.support.platform import is_freebsd, is_linux
from zscams.agent.src.support.ssh import add_to_authorized_keys
from zscams.agent.src.support.cli import ensure_config_value, prompt, prompt_auth_info

logger = get_logger("bootstrap")


def bootstrap():
    """Ensure the agent is bootstrapped with the backend."""

    ensure_config_value(
        config_key_path="bootstrap.base_url",
        prompt_message="Bootstrap server origin",
        prompt_desc="(E.g. http://10.0.100.100:5000)",
        process_value=lambda v: (
            v.rstrip("/") + "/api"
            if not v.rstrip("/").endswith("api")
            else v.rstrip("/")
        ),
    )

    ensure_config_value(
        config_key_path="remote.host",
        prompt_message="Remote host IP",
        prompt_desc="(E.g. 10.0.100.100)",
    )

    if backend_client.is_bootstrapped():
        logger.info("Agent ID %s is already bootstrapped.", backend_client.agent_id)
        return

    if not backend_client.is_authenticated():
        username, totp = prompt_auth_info()
        backend_client.login(username, totp)

    customer_name = prompt(
        "Customer Name",
        required=True,
    )
    connector_name = prompt(
        "Connector Name",
        "[Unique name for this connector]",
        required=True,
    )
    equipment_type = prompt(
        "Equipment Type",
        required=True,
        one_of=["ZPA", "VZEN", "PSE"],
    )
    equipment_name = (
        f"{equipment_type.lower()}-{customer_name.lower()}-{connector_name.lower()}"
    )
    enforced_id = prompt("Enforced ID", "Enforced Agent ID")
    if not os.path.exists(CONFIG_PATH):
        os.remove(CONFIG_PATH)
    config.reinitialize(equipment_name=equipment_name, equipment_type=equipment_type)
    cm_info = backend_client.bootstrap(equipment_name, enforced_id or None)

    sys_user = cast(str, cm_info.get("ssh_user"))

    create_system_user(sys_user)
    add_to_authorized_keys(sys_user, cm_info.get("server_ssh_pub_key"))
    install_zscams_systemd_service(sys_user)
    set_dirs_permissions(sys_user)


def set_dirs_permissions(user: str):
    paths = [
        ROOT_PATH.joinpath("certificates"),
        ROOT_PATH.joinpath("keys"),
    ]
    for path in paths:
        set_directory_ownership_and_permissions(path, "zscams", 0o400)

    set_directory_ownership_and_permissions(f"/home/{user}/.ssh", "zscams", 0o700)


def install_zscams_systemd_service(user_to_run_as: str):
    """Install the zscams systemd service."""
    if not is_freebsd() and not is_linux():
        logger.error("Unsupported OS for service installation.")
        return

    data = {
        "pythonpath": sysconfig.get_paths()["purelib"],
        "python_exec": sys.executable,
        "user_to_run_as": user_to_run_as,
    }

    file_prefix = "freebsd" if is_freebsd() else "linux"

    logger.debug(
        "Installing zscams systemd service for %s with data: %s", file_prefix, data
    )

    template_path = ROOT_PATH.joinpath(f"configuration/{file_prefix}_service.j2")
    with open(template_path, encoding="utf-8") as f:
        template = f.read()

    rendered_config = template.format(**data)

    install_service("zscams" if is_freebsd() else "zscams.service", rendered_config)
