# Copyright (C) 2026 GoodData Corporation

"""
Command-output summarization.

This contains `format_command_summary` (summary-first output shaping) and verbose fallback formatting.
"""

from __future__ import annotations

from pathlib import Path

from aida_mcp.output.log_utils import extract_error_payload, extract_error_payload_from_lines, read_log_tail
from aida_mcp.output.policy import MAX_ERROR_LINES

STDERR_PREVIEW_LINES = 50

# Maximum lines to show in verbose mode to prevent extremely large outputs
VERBOSE_MAX_LINES = 500


def _format_verbose_output(
    command: str,
    exit_code: int,
    stdout: str,
    stderr: str,
    log_path: Path | None = None,
) -> str:
    """
    Format full command output for verbose mode (no truncation except for extreme cases).

    Used when debugging failures that require complete stack traces.
    """
    result = [
        f"Command: {command}",
        f"Exit Code: {exit_code}",
        "",
        f"❌ FAILED (exit code: {exit_code})",
        "",
        "=" * 60,
        "VERBOSE OUTPUT (full details for debugging)",
        "=" * 60,
        "",
    ]

    combined_output = ""
    if stdout.strip():
        combined_output = stdout.strip()
    if stderr.strip():
        if combined_output:
            combined_output += "\n\n--- stderr ---\n" + stderr.strip()
        else:
            combined_output = stderr.strip()

    if combined_output:
        lines = combined_output.split("\n")
        if len(lines) > VERBOSE_MAX_LINES:
            # Even verbose mode has a safety limit
            result.append(f"(Output has {len(lines)} lines, showing last {VERBOSE_MAX_LINES})")
            result.append("")
            result.extend(lines[-VERBOSE_MAX_LINES:])
        else:
            result.extend(lines)
    else:
        result.append("(No output captured)")

    if log_path:
        result.append("")
        result.append(f"📄 Full log saved to: {log_path}")

    return "\n".join(result)


def format_command_summary(
    command: str,
    exit_code: int,
    stdout: str,
    stderr: str,
    *,
    log_path: Path | None = None,
    stderr_preview_lines: int = STDERR_PREVIEW_LINES,
    verbose: bool = False,
) -> str:
    """
    Format command output as a SUMMARY (not full output).

    Instead of returning massive outputs, this extracts key information
    and provides actionable summaries.
    """
    # Import here to avoid circular imports - parsers import from base
    from aida_mcp.output.gradle_parser import extract_detekt_summary, extract_spotless_summary
    from aida_mcp.output.python_parser import extract_ruff_summary, extract_types_summary
    from aida_mcp.output.test_summary import create_test_failure_summary, extract_test_summary

    # Verbose mode: return full output on failure for debugging
    if verbose and exit_code != 0:
        return _format_verbose_output(command, exit_code, stdout, stderr, log_path)

    result = [
        f"Command: {command}",
        f"Exit Code: {exit_code}",
        "",
    ]

    if exit_code == 0:
        result.append("✅ PASSED")
    else:
        result.append(f"❌ FAILED (exit code: {exit_code})")

    command_lower = command.lower()

    log_tail = read_log_tail(log_path) if log_path else []
    tail_text = "\n".join(log_tail) if log_tail else ((stdout or "") + "\n" + (stderr or "")).strip()

    # Extract summary based on command type (prefer log tail)
    if "test" in command_lower or "pytest" in command_lower:
        if exit_code == 0:
            test_summary = extract_test_summary(tail_text, "")
            if test_summary:
                result.append("")
                result.append(test_summary)
        else:
            failure_summary = create_test_failure_summary(tail_text, "")
            if failure_summary:
                result.append("")
                result.extend(failure_summary.splitlines())
    elif "detekt" in command_lower:
        detekt_summary = extract_detekt_summary(tail_text, "")
        if detekt_summary:
            result.append("")
            result.append(detekt_summary)
    elif "spotless" in command_lower:
        spotless_summary = extract_spotless_summary(tail_text, "")
        if spotless_summary:
            result.append("")
            result.append(spotless_summary)
    elif "ruff" in command_lower:
        ruff_summary = extract_ruff_summary(tail_text, "")
        if ruff_summary:
            result.append("")
            result.append(ruff_summary)
    elif "ty" in command_lower or "types" in command_lower:
        types_summary = extract_types_summary(tail_text, "")
        if types_summary:
            result.append("")
            result.append(types_summary)

    # For errors, show only the last MAX_ERROR_LINES from log tail.
    if exit_code != 0:
        if log_path:
            errors, error_count, truncated = extract_error_payload(log_path, max_errors=MAX_ERROR_LINES)
        else:
            errors, error_count, truncated = extract_error_payload_from_lines(
                tail_text.splitlines(),
                max_errors=MAX_ERROR_LINES,
            )
        if errors:
            result.append("")
            result.append("=== Error Details ===")
            result.extend(errors)
            if truncated:
                result.append(f"... ({max(error_count - len(errors), 0)} more errors omitted)")
            result.append("Fix the errors above and re-run validation to see remaining issues")

    # Always surface a log path on failures. Even if the summary isn't truncated,
    # users often still need the full output for root-cause analysis.
    if log_path:
        result.append("")
        result.append(f"📄 Full log: {log_path}")

    return "\n".join(result)
