"""CLI entry point for infra-diagram."""

from __future__ import annotations

import json
import sys
from pathlib import Path

import click
from rich.console import Console
from rich.panel import Panel

from . import __version__
from .demo import DEMOS
from .models import InfraDiagram, SourceType
from .output.console import render_diagram_info
from .output.html_report import export_html
from .parsers.compose import parse_compose
from .parsers.kubernetes import parse_kubernetes
from .parsers.terraform import parse_terraform
from .renderers.mermaid import render_mermaid

console = Console()


def _detect_source_type(path: str) -> SourceType:
    """Auto-detect IaC source type from files."""
    p = Path(path)
    if p.is_file():
        if p.suffix == ".tf":
            return SourceType.TERRAFORM
        if p.suffix in (".yaml", ".yml"):
            content = p.read_text(errors="ignore")
            if "apiVersion" in content and "kind" in content:
                return SourceType.KUBERNETES
            if "services:" in content:
                return SourceType.DOCKER_COMPOSE
    elif p.is_dir():
        if list(p.glob("*.tf")) or list(p.glob("**/*.tf")):
            return SourceType.TERRAFORM
        for name in ("docker-compose.yml", "docker-compose.yaml", "compose.yml", "compose.yaml"):
            if (p / name).exists():
                return SourceType.DOCKER_COMPOSE
        yaml_files = list(p.glob("**/*.yaml")) + list(p.glob("**/*.yml"))
        for yf in yaml_files:
            try:
                content = yf.read_text(errors="ignore")
                if "apiVersion" in content and "kind" in content:
                    return SourceType.KUBERNETES
            except Exception:
                pass
    return SourceType.UNKNOWN


def _parse_by_type(path: str, source_type: SourceType) -> InfraDiagram:
    """Parse files based on source type."""
    if source_type == SourceType.TERRAFORM:
        return parse_terraform(path)
    if source_type == SourceType.KUBERNETES:
        return parse_kubernetes(path)
    if source_type == SourceType.DOCKER_COMPOSE:
        return parse_compose(path)
    return InfraDiagram()


def _diagram_to_dict(diagram: InfraDiagram) -> dict:
    return {
        "title": diagram.title,
        "source_type": diagram.source_type.value,
        "node_count": diagram.node_count,
        "edge_count": diagram.edge_count,
        "source_files": diagram.source_files,
        "nodes": [
            {
                "id": n.id,
                "name": n.name,
                "type": n.node_type.value,
                "provider": n.provider,
                "properties": {k: v for k, v in n.properties.items() if not isinstance(v, set)},
            }
            for n in diagram.nodes
        ],
        "edges": [
            {"source": e.source, "target": e.target, "label": e.label}
            for e in diagram.edges
        ],
        "groups": [
            {"id": g.id, "name": g.name, "node_count": len(g.node_ids)}
            for g in diagram.groups
        ],
    }


@click.group()
@click.version_option(__version__, prog_name="infra-diagram")
def cli():
    """🏗️ infra-diagram — Infrastructure Diagram Generator.

    Generate architecture diagrams from Terraform, Kubernetes, and
    Docker Compose files. Outputs Mermaid diagrams, HTML reports,
    and JSON exports.
    """


@cli.command()
@click.argument("path", type=click.Path(exists=True), default=".")
@click.option("--type", "source_type", type=click.Choice(["auto", "terraform", "kubernetes", "compose"], case_sensitive=False), default="auto", help="Source type")
@click.option("--html", type=click.Path(), help="Export HTML report with diagram")
@click.option("--json-output", "-j", "json_out", type=click.Path(), help="Export JSON")
@click.option("--mermaid", "-m", "mermaid_out", type=click.Path(), help="Export Mermaid .md file")
@click.option("--direction", type=click.Choice(["TB", "LR", "BT", "RL"]), default="LR", help="Diagram direction")
def generate(path: str, source_type: str, html: str | None, json_out: str | None, mermaid_out: str | None, direction: str):
    """Generate infrastructure diagram from IaC files.

    Examples:

        infra-diagram generate .

        infra-diagram generate ./terraform --html diagram.html

        infra-diagram generate k8s/ --type kubernetes -m arch.md

        infra-diagram generate . --type compose --direction TB
    """
    if source_type == "auto":
        detected = _detect_source_type(path)
        if detected == SourceType.UNKNOWN:
            console.print("[red]Could not auto-detect source type. Use --type to specify.[/]")
            sys.exit(1)
        st = detected
    else:
        type_map = {"terraform": SourceType.TERRAFORM, "kubernetes": SourceType.KUBERNETES, "compose": SourceType.DOCKER_COMPOSE}
        st = type_map[source_type]

    diagram = _parse_by_type(path, st)

    if diagram.node_count == 0:
        console.print("[yellow]No infrastructure components found.[/]")
        return

    render_diagram_info(diagram)

    # Mermaid output
    mermaid_code = render_mermaid(diagram, direction=direction)
    console.print(Panel(mermaid_code, title="[bold]Mermaid Diagram[/]", border_style="blue"))

    if mermaid_out:
        Path(mermaid_out).write_text(f"```mermaid\n{mermaid_code}\n```\n", encoding="utf-8")
        console.print(f"[green]Mermaid file → {mermaid_out}[/]")

    if json_out:
        Path(json_out).write_text(json.dumps(_diagram_to_dict(diagram), indent=2), encoding="utf-8")
        console.print(f"[green]JSON report → {json_out}[/]")

    if html:
        export_html(diagram, html)
        console.print(f"[green]HTML report → {html}[/]")


@cli.command()
@click.option("--type", "demo_type", type=click.Choice(["all", "terraform", "kubernetes", "compose"], case_sensitive=False), default="all", help="Demo type")
@click.option("--html", type=click.Path(), help="Export HTML report")
@click.option("--direction", type=click.Choice(["TB", "LR", "BT", "RL"]), default="LR", help="Diagram direction")
def demo(demo_type: str, html: str | None, direction: str):
    """Run demo with sample infrastructure files.

    Examples:

        infra-diagram demo

        infra-diagram demo --type terraform

        infra-diagram demo --type compose --html compose-diagram.html
    """
    import tempfile

    console.print()
    console.print("[bold blue]🏗️ infra-diagram — Demo Mode[/]")
    console.print("[dim]Generating diagrams from sample IaC files...[/]\n")

    if demo_type == "all":
        demos = list(DEMOS.items())
    else:
        demos = [(demo_type, DEMOS[demo_type])]

    for name, (filename, content) in demos:
        console.print(f"\n[bold]━━━ {name.upper()} ({filename}) ━━━[/]\n")

        with tempfile.TemporaryDirectory() as tmpdir:
            fpath = Path(tmpdir) / filename
            fpath.write_text(content, encoding="utf-8")

            type_map = {"terraform": SourceType.TERRAFORM, "kubernetes": SourceType.KUBERNETES, "compose": SourceType.DOCKER_COMPOSE}
            st = type_map.get(name, SourceType.UNKNOWN)
            diagram = _parse_by_type(str(fpath) if st != SourceType.DOCKER_COMPOSE else tmpdir, st)

            if diagram.node_count > 0:
                render_diagram_info(diagram)
                mermaid_code = render_mermaid(diagram, direction=direction)
                console.print(Panel(mermaid_code, title=f"[bold]{name} Mermaid[/]", border_style="blue"))

                if html and name == demos[-1][0]:
                    export_html(diagram, html)
                    console.print(f"[green]HTML report → {html}[/]")
            else:
                console.print("[yellow]No components found.[/]")
