"""complyform generate — read complyform.init.yaml, emit compliant Terraform."""

from __future__ import annotations

import json
import shutil
import sys
from pathlib import Path
from typing import Annotated, Any

import typer
from rich.panel import Panel

from complyform.cli.exit_codes import EXIT_SUCCESS
from complyform.cli.main import AppContext, app
from complyform.core.auth.tier_enforcement import (
    check_framework_access,
    default_community_tier_info,
    resolve_tier_info,
)
from complyform.core.errors import (
    OutputDirectoryNotEmptyError,
    ProfileBundleError,
)
from complyform.core.greenfield.config import load_init_config
from complyform.core.greenfield.config_merger import merge_required_configs
from complyform.core.greenfield.dependency_resolver import resolve_dependencies
from complyform.core.greenfield.renderer import GenerateContext, render_terraform
from complyform.core.greenfield.service_catalog import load_service_catalog

_GF = "Greenfield (New Infrastructure)"


@app.command(name="generate", rich_help_panel=_GF)
def generate_cmd(
    ctx: typer.Context,
    config: Annotated[
        Path,
        typer.Option("--config", help="Path to complyform.init.yaml"),
    ] = Path("./complyform.init.yaml"),
    force: Annotated[
        bool,
        typer.Option("--force", help="Overwrite non-empty output directory"),
    ] = False,
    format: Annotated[
        str,
        typer.Option("--format", help="Output format: terminal, json"),
    ] = "terminal",
) -> None:
    """Generate compliant infrastructure-as-code templates."""
    app_ctx: AppContext = ctx.obj

    # Step 1: Load init config
    init_config = load_init_config(config)

    cloud = init_config.cloud
    output_dir = Path(init_config.output_directory)

    # Check output directory
    if output_dir.exists() and any(output_dir.iterdir()) and not force:
        raise OutputDirectoryNotEmptyError(str(output_dir))

    # Step 2: Tier gating — greenfield generation = remediation
    tier_info = _get_tier_info(app_ctx)
    check_framework_access(
        init_config.frameworks,
        "remediate",
        tier_info,
    )

    # Step 3: Load service catalog + framework mappings, collect required_configs
    catalog = load_service_catalog(cloud)
    all_configs: dict[str, list[tuple[str, str, dict[str, Any]]]] = {}
    all_deps: list[dict[str, Any]] = []

    for framework_id in init_config.frameworks:
        try:
            from complyform.core.profiles.mapping_loader import load_mappings

            mapping_file = load_mappings(framework_id, cloud)
        except ProfileBundleError:
            # No mappings for this framework/cloud combination — skip
            continue

        for mapping in mapping_file.mappings:
            if mapping.required_config is None:
                continue

            # Check if any of the mapping's resource types match selected services
            selected_resource_types: set[str] = set()
            for svc_entry in init_config.services:
                svc = catalog.get_service(svc_entry.id)
                if svc is not None:
                    selected_resource_types.update(svc.resource_types)

            for rt in mapping.resource_types:
                if rt in selected_resource_types:
                    if rt not in all_configs:
                        all_configs[rt] = []
                    all_configs[rt].append(
                        (framework_id, mapping.control_id, mapping.required_config)
                    )

            # Collect dependencies
            for dep in mapping.dependencies:
                all_deps.append(
                    {
                        "template": dep.template,
                        "resource_type": dep.resource_type,
                        "required_by": ", ".join(mapping.resource_types),
                    }
                )

    # Step 4: Merge configs and resolve dependencies
    merged_configs: dict[str, dict[str, Any]] = {}
    compliance_comments: dict[str, list[str]] = {}

    for resource_type, configs in all_configs.items():
        merged, trace = merge_required_configs(configs)
        merged_configs[resource_type] = merged
        compliance_comments[resource_type] = trace

    # Apply service catalog defaults for resource types without framework overrides
    for svc_entry in init_config.services:
        svc = catalog.get_service(svc_entry.id)
        if svc is None:
            continue
        for rt in svc.resource_types:
            if rt not in merged_configs and svc.default_config:
                merged_configs[rt] = dict(svc.default_config)

    dependencies = resolve_dependencies(all_deps)

    # Step 5: Render templates
    services_full = []
    for svc_entry in init_config.services:
        svc = catalog.get_service(svc_entry.id)
        if svc is not None:
            services_full.append(svc)

    gen_context = GenerateContext(
        project_id=init_config.project_id,
        cloud=cloud,
        org_id=init_config.org_id,
        region=init_config.region,
        frameworks=init_config.frameworks,
        services=services_full,
        merged_configs=merged_configs,
        dependencies=dependencies,
        compliance_comments=compliance_comments,
    )

    generated_files = render_terraform(gen_context, output_dir)

    # Copy init config to output
    init_copy_path = output_dir / "complyform.init.yaml"
    if config.resolve() != init_copy_path.resolve():
        shutil.copy2(config, init_copy_path)
        generated_files.append(init_copy_path)

    if format == "json":
        envelope = {
            "schema_version": 1,
            "command": "generate",
            "cloud": cloud,
            "frameworks": init_config.frameworks,
            "services": [s.id for s in init_config.services],
            "output_directory": str(output_dir),
            "files_generated": [str(f) for f in generated_files],
            "resource_count": sum(len(s.resource_types) for s in services_full),
            "dependency_count": len(dependencies),
            "compliance_frameworks_applied": init_config.frameworks,
            "next_steps": [
                f"cd {output_dir}",
                "cp terraform.tfvars.example terraform.tfvars",
                "tofu init && tofu plan",
            ],
        }
        sys.stdout.write(json.dumps(envelope, indent=2) + "\n")
    else:
        console = app_ctx.console
        file_list = "\n".join(f"  {f}" for f in generated_files)
        console.print(
            Panel(
                f"Files generated:\n{file_list}\n\n"
                f"Resources: {sum(len(s.resource_types) for s in services_full)}\n"
                f"Dependencies: {len(dependencies)}\n"
                f"Frameworks: {', '.join(init_config.frameworks)}\n\n"
                f"Next steps:\n"
                f"  cd {output_dir}\n"
                f"  cp terraform.tfvars.example terraform.tfvars\n"
                f"  tofu init && tofu plan",
                title="Generate Complete",
                style="green",
            )
        )

    raise typer.Exit(EXIT_SUCCESS)


def _get_tier_info(app_ctx: AppContext) -> Any:
    """Get TierInfo from license cache or community defaults."""
    try:
        from complyform.core.auth.license import LicenseManager

        mgr = LicenseManager()
        cache = mgr.load_cache()
        return resolve_tier_info(cache)
    except Exception:
        return default_community_tier_info()
