"""Typer app skeleton with global flags, error handling, and stub commands.

All progress/warnings go to stderr. Stdout is reserved for --format=json piping.
"""

from __future__ import annotations

import os
from dataclasses import dataclass
from typing import TYPE_CHECKING, Annotated

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

# Guarantee spinner registration before any command runs.
import complyform.cli.spinner as _spinner  # noqa: F401
from complyform.cli.exit_codes import (
    EXIT_INTERRUPTED,
    EXIT_RUNTIME_ERROR,
)
from complyform.core.config import (
    ComplyFormConfig,
    load_config,
    resolve_config_path,
)
from complyform.core.errors import ComplyFormError, MutualExclusivityError

if TYPE_CHECKING:
    from pathlib import Path

app = typer.Typer(
    name="complyform",
    help=("Compliance-as-code CLI for GCP, AWS, and Azure infrastructure."),
    rich_markup_mode="rich",
)

_stderr_console = Console(stderr=True)


@dataclass
class AppContext:
    """Resolved global state passed via typer.Context."""

    verbose: bool
    quiet: bool
    no_progress: bool
    config_path: Path
    config: ComplyFormConfig
    console: Console


def _env_bool(name: str) -> bool | None:
    """Read a boolean env var. Returns None if unset."""
    val = os.environ.get(name)
    if val is None:
        return None
    return val.lower() in ("1", "true", "yes")


def _version_callback(value: bool | None) -> None:
    """Print branded banner + version and exit."""
    if value:
        from complyform import __version__
        from complyform.cli.banner import print_banner, should_show_banner

        if should_show_banner():
            console = Console(stderr=True)
            print_banner(console, __version__)
        else:
            typer.echo(f"complyform {__version__}")
        raise typer.Exit()


@app.callback(invoke_without_command=True)
def main_callback(
    ctx: typer.Context,
    verbose: Annotated[
        bool,
        typer.Option("--verbose", "-v", help="Show debug output"),
    ] = False,
    quiet: Annotated[
        bool,
        typer.Option("--quiet", "-q", help="Suppress non-error output"),
    ] = False,
    no_progress: Annotated[
        bool,
        typer.Option("--no-progress", help="Suppress progress indicators"),
    ] = False,
    config: Annotated[
        str | None,
        typer.Option("--config", "-c", help="Config file path"),
    ] = None,
    version: Annotated[
        bool | None,
        typer.Option(
            "--version",
            help="Show version and exit",
            is_eager=True,
            callback=_version_callback,
        ),
    ] = None,
) -> None:
    """Global flags applied before any subcommand."""
    env_verbose = _env_bool("COMPLYFORM_VERBOSE")
    if env_verbose is not None and not verbose:
        verbose = env_verbose

    env_no_progress = _env_bool("COMPLYFORM_NO_PROGRESS")
    if env_no_progress is not None and not no_progress:
        no_progress = env_no_progress

    if verbose and quiet:
        raise MutualExclusivityError(
            "Cannot use --verbose and --quiet together.",
            "Use one or the other.",
        )

    env_config = os.environ.get("COMPLYFORM_CONFIG")
    resolved = config or (None if env_config is None else env_config)
    config_path = resolve_config_path(resolved)
    cfg = load_config(config_path)

    ctx.ensure_object(dict)
    ctx.obj = AppContext(
        verbose=verbose,
        quiet=quiet,
        no_progress=no_progress,
        config_path=config_path,
        config=cfg,
        console=_stderr_console,
    )

    if ctx.invoked_subcommand is None:
        # Bare `complyform` — show banner + help
        from complyform.cli.banner import print_banner, should_show_banner

        if should_show_banner(quiet=quiet):
            from complyform import __version__

            console = Console(stderr=True)
            print_banner(console, __version__)
        typer.echo(ctx.get_help())
        raise typer.Exit()


# -------------------------------------------------------------------
# Stub command helper
# -------------------------------------------------------------------


def _stub(name: str) -> None:
    """Raise not-implemented error for stub commands."""
    raise ComplyFormError(
        title="Not Yet Implemented",
        message=f"The '{name}' command is not yet available.",
        fix="This command will be added in a future release.",
    )


# -------------------------------------------------------------------
# Brownfield (Existing Infrastructure)
# -------------------------------------------------------------------

_BF = "Brownfield (Existing Infrastructure)"


# assess command registered via late import of assess_cmd.py


# remediate command registered via late import of remediate_cmd.py
# fix command registered via late import of fix_cmd.py


# explain command registered via late import of explain_cmd.py


# validate command registered via late import of validate_cmd.py


# report command registered via late import of report_cmd.py


# policy-gen command registered via late import of policy_gen_cmd.py


# export command registered via late import of export_cmd.py


# -------------------------------------------------------------------
# Greenfield (New Infrastructure)
# -------------------------------------------------------------------

_GF = "Greenfield (New Infrastructure)"


# init and generate registered via late import of init_cmd.py and generate_cmd.py


# -------------------------------------------------------------------
# Discovery
# -------------------------------------------------------------------


# frameworks command group is registered via late import below


# -------------------------------------------------------------------
# Management
# -------------------------------------------------------------------

_MG = "Management"


# config subcommand group is registered via late import below


@app.command(rich_help_panel=_MG)
def dashboard(ctx: typer.Context) -> None:
    """Open the compliance dashboard."""
    _stub("dashboard")


# feedback command registered via late import of feedback_cmd.py


# -------------------------------------------------------------------
# Late imports: real command implementations replace stubs above
# -------------------------------------------------------------------

import complyform.cli.assess_cmd as _assess_cmd  # noqa: E402, F401
import complyform.cli.dashboard_cmd as _dashboard_cmd  # noqa: E402, F401
import complyform.cli.doctor_cmd as _doctor_cmd  # noqa: E402, F401
import complyform.cli.explain_cmd as _explain_cmd  # noqa: E402, F401
import complyform.cli.export_cmd as _export_cmd  # noqa: E402, F401
import complyform.cli.feedback_cmd as _feedback_cmd  # noqa: E402, F401
import complyform.cli.fix_cmd as _fix_cmd  # noqa: E402, F401
import complyform.cli.generate_cmd as _generate_cmd  # noqa: E402, F401
import complyform.cli.init_cmd as _init_cmd  # noqa: E402, F401
import complyform.cli.mcp_server as _mcp_server  # noqa: E402, F401
import complyform.cli.policy_gen_cmd as _policy_gen_cmd  # noqa: E402, F401
import complyform.cli.remediate_cmd as _remediate_cmd  # noqa: E402, F401
import complyform.cli.report_cmd as _report_cmd  # noqa: E402, F401
import complyform.cli.scan_cmd as _scan_cmd  # noqa: E402, F401
import complyform.cli.update_cmd as _update_cmd  # noqa: E402, F401
import complyform.cli.validate_cmd as _validate_cmd  # noqa: E402, F401
import complyform.cli.verify_cmd as _verify_cmd  # noqa: E402, F401
from complyform.cli.config_cmd import config_app as _cfg_app  # noqa: E402
from complyform.cli.frameworks_cmd import frameworks_app as _fw_app  # noqa: E402

app.add_typer(_fw_app, rich_help_panel="Discovery")
app.add_typer(_cfg_app, rich_help_panel=_MG)

# -------------------------------------------------------------------
# Entry point
# -------------------------------------------------------------------


def main() -> None:
    """Global error handler wrapping the Typer app."""
    try:
        app()
    except ComplyFormError as e:
        e.display(_stderr_console)
        raise SystemExit(EXIT_RUNTIME_ERROR) from None
    except KeyboardInterrupt:
        _stderr_console.print("\n[dim]Interrupted[/dim]")
        raise SystemExit(EXIT_INTERRUPTED) from None
    except SystemExit:
        raise
    except Exception as e:
        _stderr_console.print(
            Panel(
                f"Unexpected error: {e}\n\n"
                "Please report this:"
                " complyform feedback --bug",
                title="✗ Internal Error",
                style="red",
            ),
        )
        raise SystemExit(EXIT_RUNTIME_ERROR) from None
