from __future__ import annotations

from typing import TextIO

from .errors import ProxmoxError, SettingsError
from .services.factory import ProxmoxServiceFactory
from .settings import AppSettings


def run_live_doctor(
    settings: AppSettings,
    *,
    stream: TextIO,
    service_factory: type[ProxmoxServiceFactory] = ProxmoxServiceFactory,
) -> int:
    try:
        settings.validate_live_requirements()
        settings.safety_policy.validate()
    except SettingsError as exc:
        stream.write(f"FAIL configuration: {exc}\n")
        return 1

    stream.write("Target\n")
    stream.write(f"  host: {settings.sanitized_host}\n")
    stream.write(f"  api_base: {settings.proxmox_api_base}\n")
    stream.write(f"  realm: {settings.proxmox_realm}\n")
    stream.write(f"  verify_tls: {settings.proxmox_verify_tls}\n")
    stream.write(f"  prevent_create: {settings.safety_policy.prevent_create}\n")
    stream.write(f"  enable_test_mode: {settings.safety_policy.enable_test_mode}\n")

    service = service_factory.create(settings)

    try:
        stream.write("1. Checking HTTPS reachability...\n")
        transport_status = service.check_connectivity()
        stream.write(f"   OK {transport_status}\n")

        stream.write("2. Checking API base path...\n")
        release = service.check_api_base()
        stream.write(f"   OK release={release}\n")

        stream.write("3. Loading realms...\n")
        realms = service.load_realms()
        stream.write(f"   OK realms={','.join(realm.name for realm in realms)}\n")

        stream.write("4. Attempting login...\n")
        session = service.login(
            settings.proxmox_user or "",
            settings.proxmox_password or "",
            settings.proxmox_realm or "",
        )
        stream.write(f"   OK authenticated_as={session.username}\n")

        if settings.safety_policy.enable_test_mode:
            stream.write("5. Validating test mode create scope...\n")
            nodes = {node.name for node in service.load_nodes()}
            if settings.safety_policy.test_node not in nodes:
                raise SettingsError(
                    f"Configured test node {settings.safety_policy.test_node!r} was not found."
                )
            stream.write(f"   OK node={settings.safety_policy.test_node}\n")
            if settings.safety_policy.test_pool:
                pools = {pool.poolid for pool in service.load_pools()}
                if settings.safety_policy.test_pool not in pools:
                    raise SettingsError(
                        f"Configured test pool {settings.safety_policy.test_pool!r} was not found."
                    )
                stream.write(f"   OK pool={settings.safety_policy.test_pool}\n")
            stream.write(f"   tag={settings.safety_policy.test_tag}\n")
            stream.write(f"   name_prefix={settings.safety_policy.test_vm_name_prefix}\n")
    except (ProxmoxError, SettingsError, ValueError) as exc:
        stream.write(f"FAIL {exc}\n")
        return 1
    finally:
        close = getattr(service, "close", None)
        if callable(close):
            close()

    stream.write("Doctor finished successfully.\n")
    return 0
