"""Output formatters for CI review results.

Formats ReviewResult as GitHub PR comments, Markdown summary, or
exit codes for CI pass/fail control.
"""

from __future__ import annotations

from triad.schemas.ci import ReviewResult

# Severity → emoji mapping for Markdown
_SEVERITY_ICON: dict[str, str] = {
    "critical": "🔴",
    "warning": "🟡",
    "suggestion": "🔵",
}


def format_github_comments(result: ReviewResult) -> list[dict]:
    """Format findings as GitHub PR review comments.

    Each finding with a file and line becomes a GitHub inline comment.
    Findings without line numbers are included as general comments.

    Returns:
        List of dicts with keys: path, line (or None), body, side.
    """
    comments: list[dict] = []

    for finding in result.findings:
        body_parts = [
            f"**{finding.severity.upper()}**: {finding.description}",
        ]
        if finding.suggestion:
            body_parts.append(f"\n**Suggestion:** {finding.suggestion}")

        reporters = ", ".join(finding.reported_by) if finding.reported_by else "unknown"
        confirmed_tag = " ✅ Confirmed" if finding.confirmed else ""
        body_parts.append(f"\n_Reported by: {reporters}{confirmed_tag}_")

        body = "\n".join(body_parts)

        comment: dict = {
            "path": finding.file,
            "body": body,
            "side": "RIGHT",
        }
        if finding.line is not None:
            comment["line"] = finding.line

        comments.append(comment)

    return comments


def format_summary(result: ReviewResult) -> str:
    """Format a Markdown summary suitable for a PR comment body.

    Includes consensus recommendation, findings by severity,
    model agreement breakdown, and cost.
    """
    lines: list[str] = []

    # Consensus banner
    if result.consensus_recommendation == "approve":
        lines.append("## ✅ CRTX Review: Approved")
    else:
        lines.append("## ⚠️ CRTX Review: Changes Requested")
    lines.append("")

    # Summary stats
    lines.append(
        f"**{result.total_findings} findings** "
        f"({result.critical_count} critical) | "
        f"**{len(result.models_used)} models** | "
        f"**${result.total_cost:.4f}** | "
        f"**{result.duration_seconds:.1f}s**"
    )
    lines.append("")

    # Findings by severity
    if result.findings:
        lines.append("### Findings")
        lines.append("")

        # Sort: critical first, then warning, then suggestion
        severity_order = {"critical": 0, "warning": 1, "suggestion": 2}
        sorted_findings = sorted(
            result.findings,
            key=lambda f: severity_order.get(f.severity, 3),
        )

        for f in sorted_findings:
            icon = _SEVERITY_ICON.get(f.severity, "⚪")
            line_ref = f" (L{f.line})" if f.line else ""
            confirmed = " ✅" if f.confirmed else ""
            lines.append(
                f"- {icon} **{f.severity.upper()}** "
                f"`{f.file}{line_ref}`{confirmed}: {f.description}"
            )
            if f.suggestion:
                lines.append(f"  - 💡 {f.suggestion}")

        lines.append("")

    # Model agreement
    if result.model_assessments:
        lines.append("### Model Assessments")
        lines.append("")
        lines.append("| Model | Recommendation | Findings | Cost |")
        lines.append("|-------|---------------|----------|------|")
        for a in result.model_assessments:
            rec_icon = "✅" if a.recommendation == "approve" else "⚠️"
            lines.append(
                f"| {a.model_key} | {rec_icon} {a.recommendation} | "
                f"{len(a.findings)} | ${a.cost:.4f} |"
            )
        lines.append("")

    # Footer
    lines.append("---")
    lines.append("*Generated by [CRTX](https://github.com/triad-ai/crtx)*")
    lines.append("")

    return "\n".join(lines)


def format_exit_code(
    result: ReviewResult,
    fail_on: str = "critical",
) -> int:
    """Determine the CI exit code from a review result.

    Args:
        result: The review result.
        fail_on: When to fail — "critical", "warning", or "any".

    Returns:
        0 if pass, 1 if fail (findings match threshold), 2 if error.
    """
    if not result.model_assessments:
        return 2  # No assessments = error

    if fail_on == "any" and result.total_findings > 0:
        return 1

    if fail_on == "warning":
        has_warning_or_above = any(
            f.severity in ("critical", "warning") for f in result.findings
        )
        if has_warning_or_above:
            return 1

    if fail_on == "critical" and result.critical_count > 0:
        return 1

    return 0
