"""
Example config factory: builds SimpleConfig-compatible config dicts via core generator.

Author: Vasiliy Zdanovskiy
email: vasilyvz@gmail.com
"""

from __future__ import annotations

import json
import tempfile
from pathlib import Path
from typing import Any, Dict, List
from urllib.parse import urlparse

from mcp_proxy_adapter.core.config.simple_config import SimpleConfig
from mcp_proxy_adapter.core.config.simple_config_generator import SimpleConfigGenerator


def _generate_and_to_dict(
    protocol: str,
    with_proxy: bool = False,
    server_port: int = 8080,
    server_log_dir: str = "./logs",
    server_host: str = "0.0.0.0",
    server_cert_file: str | None = None,
    server_key_file: str | None = None,
    server_ca_cert_file: str | None = None,
    use_token: bool = False,
    tokens: Dict[str, List[str]] | None = None,
    use_roles: bool = False,
    roles: Dict[str, List[str]] | None = None,
    registration_host: str | None = None,
    registration_port: int | None = None,
    registration_server_id: str | None = None,
) -> Dict[str, Any]:
    """Generate config to temp file, load, optionally set auth/registration, return dict."""
    with tempfile.NamedTemporaryFile(suffix=".json", delete=False, mode="w") as f:
        out_path = f.name
    try:
        gen = SimpleConfigGenerator()
        gen.generate(
            protocol=protocol,
            with_proxy=with_proxy,
            out_path=out_path,
            server_host=server_host,
            server_port=server_port,
            server_log_dir=server_log_dir,
            server_cert_file=server_cert_file,
            server_key_file=server_key_file,
            server_ca_cert_file=server_ca_cert_file,
            registration_host=registration_host or "localhost",
            registration_port=registration_port or 3005,
            registration_server_id=registration_server_id,
        )
        cfg = SimpleConfig(out_path)
        cfg.load()
        if use_token or (tokens and len(tokens) > 0):
            cfg.model.auth.use_token = True
            cfg.model.auth.tokens = tokens or {"admin-secret-key": ["admin"]}
        if use_roles or (roles and len(roles) > 0):
            cfg.model.auth.use_roles = True
            cfg.model.auth.use_token = True
            cfg.model.auth.roles = roles or {"admin": ["*"]}
            if not cfg.model.auth.tokens:
                cfg.model.auth.tokens = {"admin-secret-key": ["admin"]}
        return cfg.to_dict()
    finally:
        Path(out_path).unlink(missing_ok=True)


def create_http_simple(
    port: int = 8080,
    log_dir: str = "./logs",
    host: str = "0.0.0.0",
) -> Dict[str, Any]:
    """Create HTTP config without auth or proxy."""
    return _generate_and_to_dict(
        protocol="http",
        with_proxy=False,
        server_port=port,
        server_log_dir=log_dir,
        server_host=host,
    )


def create_http_token(
    port: int = 8080,
    log_dir: str = "./logs",
    host: str = "0.0.0.0",
    api_keys: Dict[str, str] | None = None,
) -> Dict[str, Any]:
    """Create HTTP config with token auth. api_keys: role_name -> token_value."""
    tokens: Dict[str, List[str]] = {}
    if api_keys:
        for role, token in api_keys.items():
            tokens[token] = [role]
    if not tokens:
        tokens = {"admin-secret-key": ["admin"]}
    return _generate_and_to_dict(
        protocol="http",
        with_proxy=False,
        server_port=port,
        server_log_dir=log_dir,
        server_host=host,
        use_token=True,
        tokens=tokens,
    )


def create_https_simple(
    port: int = 8443,
    log_dir: str = "./logs",
    host: str = "0.0.0.0",
    cert_dir: str = "./certs",
    key_dir: str = "./keys",
) -> Dict[str, Any]:
    """Create HTTPS config. cert_dir/key_dir used for server cert/key paths."""
    cert_file = str(Path(cert_dir) / "server.crt")
    key_file = str(Path(key_dir) / "server.key")
    return _generate_and_to_dict(
        protocol="https",
        with_proxy=False,
        server_port=port,
        server_log_dir=log_dir,
        server_host=host,
        server_cert_file=cert_file,
        server_key_file=key_file,
    )


def create_https_token(
    port: int = 8443,
    log_dir: str = "./logs",
    host: str = "0.0.0.0",
    cert_dir: str = "./certs",
    key_dir: str = "./keys",
    api_keys: Dict[str, str] | None = None,
) -> Dict[str, Any]:
    """Create HTTPS config with token auth."""
    tokens: Dict[str, List[str]] = {}
    if api_keys:
        for role, token in api_keys.items():
            tokens[token] = [role]
    if not tokens:
        tokens = {"admin-secret-key": ["admin"]}
    cert_file = str(Path(cert_dir) / "server.crt")
    key_file = str(Path(key_dir) / "server.key")
    return _generate_and_to_dict(
        protocol="https",
        with_proxy=False,
        server_port=port,
        server_log_dir=log_dir,
        server_host=host,
        server_cert_file=cert_file,
        server_key_file=key_file,
        use_token=True,
        tokens=tokens,
    )


def create_mtls_simple(
    port: int = 8443,
    log_dir: str = "./logs",
    host: str = "0.0.0.0",
    cert_dir: str = "./certs",
    key_dir: str = "./keys",
) -> Dict[str, Any]:
    """Create mTLS config. CA cert required (cert_dir/ca.crt or cert_dir/../ca/ca.crt)."""
    cert_file = str(Path(cert_dir) / "server.crt")
    key_file = str(Path(key_dir) / "server.key")
    ca_file = str(Path(cert_dir) / "ca.crt")
    if not Path(ca_file).exists():
        ca_file = str(Path(cert_dir).parent / "ca" / "ca.crt")
    return _generate_and_to_dict(
        protocol="mtls",
        with_proxy=False,
        server_port=port,
        server_log_dir=log_dir,
        server_host=host,
        server_cert_file=cert_file,
        server_key_file=key_file,
        server_ca_cert_file=ca_file,
    )


def create_mtls_with_roles(
    port: int = 8443,
    log_dir: str = "./logs",
    host: str = "0.0.0.0",
    cert_dir: str = "./certs",
    key_dir: str = "./keys",
    roles: Dict[str, List[str]] | None = None,
) -> Dict[str, Any]:
    """Create mTLS config with role-based auth."""
    cert_file = str(Path(cert_dir) / "server.crt")
    key_file = str(Path(key_dir) / "server.key")
    ca_file = str(Path(cert_dir) / "ca.crt")
    if not Path(ca_file).exists():
        ca_file = str(Path(cert_dir).parent / "ca" / "ca.crt")
    return _generate_and_to_dict(
        protocol="mtls",
        with_proxy=False,
        server_port=port,
        server_log_dir=log_dir,
        server_host=host,
        server_cert_file=cert_file,
        server_key_file=key_file,
        server_ca_cert_file=ca_file,
        use_token=True,
        use_roles=True,
        tokens={"admin-secret-key-mtls": ["admin"]},
        roles=roles or {"admin": ["read", "write", "delete", "admin"]},
    )


def create_mtls_with_proxy(
    port: int = 8443,
    log_dir: str = "./logs",
    host: str = "0.0.0.0",
    cert_dir: str = "./certs",
    key_dir: str = "./keys",
    proxy_url: str = "https://127.0.0.1:3005",
    server_id: str = "mcp_test_server",
) -> Dict[str, Any]:
    """Create mTLS config with proxy registration enabled."""
    cert_file = str(Path(cert_dir) / "server.crt")
    key_file = str(Path(key_dir) / "server.key")
    ca_file = str(Path(cert_dir) / "ca.crt")
    if not Path(ca_file).exists():
        ca_file = str(Path(cert_dir).parent / "ca" / "ca.crt")
    parsed = urlparse(proxy_url)
    reg_host = parsed.hostname or "localhost"
    reg_port = parsed.port or (443 if parsed.scheme == "https" else 3005)
    return _generate_and_to_dict(
        protocol="mtls",
        with_proxy=True,
        server_port=port,
        server_log_dir=log_dir,
        server_host=host,
        server_cert_file=cert_file,
        server_key_file=key_file,
        server_ca_cert_file=ca_file,
        registration_host=reg_host,
        registration_port=reg_port,
        registration_server_id=server_id,
    )


def create_full_featured(
    port: int = 8443,
    log_dir: str = "./logs",
    host: str = "0.0.0.0",
    cert_dir: str = "./certs",
    key_dir: str = "./keys",
    proxy_url: str = "https://127.0.0.1:3005",
    server_id: str = "mcp_full_server",
) -> Dict[str, Any]:
    """Create mTLS config with proxy and token/roles (full featured)."""
    cfg = create_mtls_with_proxy(
        port=port,
        log_dir=log_dir,
        host=host,
        cert_dir=cert_dir,
        key_dir=key_dir,
        proxy_url=proxy_url,
        server_id=server_id,
    )
    with tempfile.NamedTemporaryFile(suffix=".json", delete=False, mode="w") as f:
        out_path = f.name
    try:
        Path(out_path).write_text(json.dumps(cfg, indent=2))
        c = SimpleConfig(out_path)
        c.load()
        c.model.auth.use_token = True
        c.model.auth.use_roles = True
        c.model.auth.tokens = {"admin-secret-key-mtls": ["admin"]}
        c.model.auth.roles = {"admin": ["*"], "user": ["read", "write"]}
        return c.to_dict()
    finally:
        Path(out_path).unlink(missing_ok=True)
