import argparse
import ipaddress
import sys

from nebula_cert_manager.exceptions import (
    CertManagerError,
    ConfigError,
    HostNotFoundError,
    RegistryNotFoundError,
)
from nebula_cert_manager.models import ClientInfo
from nebula_cert_manager.nebula_config import load_nebula_config
from nebula_cert_manager.pki import PKI
from nebula_cert_manager.registry import RegistryManager


def add_parser(subparsers: argparse._SubParsersAction) -> None:
    parser = subparsers.add_parser("issue", help="Issue a new client certificate")
    parser.add_argument(
        "--name", required=True, help="Certificate name (e.g., dtatarkin-laptop)"
    )
    parser.add_argument("--duration", default=None, help="Certificate duration")
    parser.set_defaults(func=run)


def issue_cert(
    registry_mgr: RegistryManager,
    pki: PKI,
    name: str,
    duration: str | None = None,
) -> ClientInfo:
    """Issue a new client certificate.

    Internally loads nebula config, resolves IP and groups.
    Returns the issued ClientInfo.
    Raises RegistryNotFoundError, ConfigError, HostNotFoundError.
    """
    if not registry_mgr.exists():
        raise RegistryNotFoundError()

    registry = registry_mgr.load()

    nebula_cfg = load_nebula_config(registry_mgr.registry_dir)
    if nebula_cfg is None or nebula_cfg.hosts is None or nebula_cfg.network is None:
        raise ConfigError(
            "nebula.config.yml is required with 'network' and 'hosts' sections."
        )

    if name not in nebula_cfg.hosts.hosts:
        raise HostNotFoundError(name)

    host_cfg = nebula_cfg.hosts.hosts[name]
    ip_addr = host_cfg.nebula_ip

    cidr = nebula_cfg.network.cidr
    prefix_len = ipaddress.ip_network(cidr, strict=False).prefixlen
    sign_ip = f"{ip_addr}/{prefix_len}"

    groups: list[str] = []
    if nebula_cfg.firewall is not None:
        groups.extend(nebula_cfg.firewall.host_groups.get(name, []))

    client = pki.sign_and_build_client_info(
        ca_cert=registry.ca.cert,
        ca_key=registry.ca.key,
        name=name,
        ip=sign_ip,
        groups=groups,
        duration=duration,
    )
    registry.clients.setdefault(name, []).append(client)

    registry_mgr.save(registry)
    return client


def run(args: argparse.Namespace) -> None:
    print(f"Issuing certificate for '{args.name}'...")
    try:
        client = issue_cert(args.registry_mgr, args.pki, args.name, args.duration)
    except CertManagerError as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)
    print(f"Certificate issued: {args.name}")
    print(f"Fingerprint: {client.fingerprint}")
