# Familiar - Self-Hosted AI Companion Platform
# Copyright (c) 2026 George Scott Foley
# ORCID: 0009-0006-4957-0540
# Email: Georgescottfoley@proton.me
# Licensed under the MIT License - see LICENSE file for details

"""
Caddy reverse proxy configuration generator.

Generates a Caddyfile that provides:
- Automatic TLS (self-signed for LAN, Let's Encrypt for public domains)
- Per-service subdomains ({service}.familiar.local)
- All upstream services on localhost-only ports

References:
- https://caddyserver.com/docs/caddyfile
- NIST SP 800-190: TLS termination for containerized services
"""

import logging
from pathlib import Path
from typing import Dict, List, Optional

from familiar.services.specs import SERVICE_SPECS, ServiceType

logger = logging.getLogger(__name__)

# Default domain suffix for LAN services
_DEFAULT_DOMAIN = "familiar.local"

# Services directory for Caddy config
_CADDY_DIR = Path.home() / ".familiar" / "services" / "caddy"


def generate_caddyfile(
    domain: str = _DEFAULT_DOMAIN,
    services: Optional[List[str]] = None,
) -> str:
    """Generate a Caddyfile for all deployed container services.

    Each service gets a subdomain entry like:
        mealie.familiar.local {
            tls internal
            reverse_proxy 127.0.0.1:9925
        }

    Args:
        domain: Base domain for subdomains (default: familiar.local)
        services: Specific service keys to include (default: all container specs)

    Returns:
        Complete Caddyfile content as a string
    """
    if services is None:
        services = [
            k
            for k, s in SERVICE_SPECS.items()
            if s.service_type == ServiceType.CONTAINER
            and s.health_check_port
            and k != "caddy"  # Caddy doesn't reverse-proxy to itself
        ]

    lines = [
        "# Familiar reverse proxy — auto-generated Caddyfile",
        "# TLS termination for all self-hosted services",
        "#",
        "# Regenerate with: familiar.services.proxy.generate_caddyfile()",
        "",
        "# Global options",
        "{",
        "    # Use internal CA for self-signed certs (LAN-safe, no Let's Encrypt needed)",
        "    local_certs",
        "}",
        "",
    ]

    # Dashboard entry — always first
    lines.extend(
        [
            f"dashboard.{domain} {{",
            "    tls internal",
            "    reverse_proxy 127.0.0.1:5000",
            "}",
            "",
        ]
    )

    # Per-service entries
    for key in sorted(services):
        spec = SERVICE_SPECS.get(key)
        if not spec or spec.service_type != ServiceType.CONTAINER:
            continue
        if not spec.health_check_port:
            continue

        # Use the health check port as the upstream port (same as the exposed port)
        upstream_port = spec.health_check_port

        # Service subdomain name (replace underscores with hyphens for DNS)
        subdomain = key.replace("_", "-")

        lines.extend(
            [
                f"{subdomain}.{domain} {{",
                "    tls internal",
                f"    reverse_proxy 127.0.0.1:{upstream_port}",
                "}",
                "",
            ]
        )

    return "\n".join(lines)


def write_caddyfile(
    domain: str = _DEFAULT_DOMAIN,
    services: Optional[List[str]] = None,
) -> Path:
    """Generate and write a Caddyfile to the Caddy config directory.

    Returns the path to the written file.
    """
    _CADDY_DIR.mkdir(parents=True, exist_ok=True)
    content = generate_caddyfile(domain=domain, services=services)
    path = _CADDY_DIR / "Caddyfile"
    path.write_text(content, encoding="utf-8")
    logger.info("Wrote Caddyfile to %s", path)
    return path


def get_service_urls(domain: str = _DEFAULT_DOMAIN) -> Dict[str, str]:
    """Get HTTPS URLs for all services via Caddy proxy.

    Returns:
        Dict mapping service key to its HTTPS URL
    """
    urls = {"dashboard": f"https://dashboard.{domain}"}

    for key, spec in SERVICE_SPECS.items():
        if spec.service_type != ServiceType.CONTAINER or not spec.health_check_port:
            continue
        if key == "caddy":
            continue  # Caddy is the proxy itself, not a proxied service
        subdomain = key.replace("_", "-")
        urls[key] = f"https://{subdomain}.{domain}"

    return urls
