"""Lint subcommand for npkt CLI."""

import json
import sys

import click

from ..linter.scp_linter import SCPLinter
from ..models.lint import LintSeverity
from .common import resolve_policy_files


@click.command()
@click.argument("policy_path", type=click.Path(exists=True))
@click.option(
    "--format",
    "-f",
    "output_format",
    type=click.Choice(["text", "json"]),
    default="text",
    help="Output format (default: text)",
)
@click.option(
    "--strict",
    is_flag=True,
    help="Treat warnings as errors (exit with non-zero status)",
)
@click.option(
    "--quiet",
    "-q",
    is_flag=True,
    help="Only show errors, suppress warnings and info",
)
def lint(
    policy_path: str,
    output_format: str,
    strict: bool,
    quiet: bool,
) -> None:
    """Lint SCP policies for errors and warnings.

    POLICY_PATH can be a single JSON file or a directory containing JSON files.

    \b
    Examples:
      npkt lint policy.json
      npkt lint ./policies/
      npkt lint policy.json --format json
      npkt lint policy.json --strict
    """
    files = resolve_policy_files(policy_path)
    linter = SCPLinter()

    all_results = []
    has_errors = False
    has_warnings = False

    for file_path in sorted(files):
        try:
            with open(file_path, encoding="utf-8") as f:
                policy_data = json.load(f)

            report = linter.lint(policy_data)
            all_results.append({"file": str(file_path), "report": report})

            if report.has_errors:
                has_errors = True
            if report.has_warnings:
                has_warnings = True

        except json.JSONDecodeError as e:
            all_results.append(
                {
                    "file": str(file_path),
                    "error": f"Invalid JSON: {e}",
                }
            )
            has_errors = True
        except OSError as e:
            all_results.append(
                {
                    "file": str(file_path),
                    "error": str(e),
                }
            )
            has_errors = True

    if output_format == "json":
        _output_json(all_results)
    else:
        _output_text(all_results, quiet)

    # Exit with appropriate code
    if has_errors:
        sys.exit(1)
    elif strict and has_warnings:
        sys.exit(1)
    else:
        sys.exit(0)


def _output_json(results: list) -> None:
    """Output results in JSON format."""
    output = []
    for item in results:
        if "error" in item:
            output.append(
                {
                    "file": item["file"],
                    "error": item["error"],
                    "results": [],
                }
            )
        else:
            report = item["report"]
            output.append(
                {
                    "file": item["file"],
                    "results": [
                        {
                            "code": r.code,
                            "severity": r.severity.value,
                            "message": r.message,
                            "location": r.location,
                        }
                        for r in report.results
                    ],
                    "summary": {
                        "errors": report.error_count,
                        "warnings": report.warning_count,
                        "info": report.info_count,
                    },
                }
            )
    click.echo(json.dumps(output, indent=2))


def _output_text(results: list, quiet: bool) -> None:
    """Output results in human-readable text format."""
    total_errors = 0
    total_warnings = 0
    total_info = 0

    for item in results:
        file_path = item["file"]

        if "error" in item:
            click.echo(f"\n{file_path}")
            click.echo(click.style(f"  ERROR: {item['error']}", fg="red"))
            total_errors += 1
            continue

        report = item["report"]

        if not report.results:
            if not quiet:
                click.echo(f"\n{file_path}")
                click.echo(click.style("  + No issues found", fg="green"))
            continue

        click.echo(f"\n{file_path}")

        for result in report.results:
            if quiet and result.severity not in (LintSeverity.ERROR,):
                continue

            if result.severity == LintSeverity.ERROR:
                color = "red"
                prefix = "E"
            elif result.severity == LintSeverity.WARNING:
                color = "yellow"
                prefix = "W"
            else:
                color = "cyan"
                prefix = "I"

            location = f" ({result.location})" if result.location else ""
            click.echo(
                click.style(f"  [{prefix}] {result.code}: ", fg=color)
                + f"{result.message}{location}"
            )

        total_errors += report.error_count
        total_warnings += report.warning_count
        total_info += report.info_count

    # Summary
    click.echo()
    if total_errors == 0 and total_warnings == 0:
        click.echo(click.style("All checks passed!", fg="green"))
    else:
        summary_parts = []
        if total_errors > 0:
            summary_parts.append(click.style(f"{total_errors} error(s)", fg="red"))
        if total_warnings > 0:
            summary_parts.append(click.style(f"{total_warnings} warning(s)", fg="yellow"))
        if total_info > 0 and not quiet:
            summary_parts.append(f"{total_info} info")
        click.echo("Summary: " + ", ".join(summary_parts))
