# Copyright (c) 2026 MergeGuide, Inc. All rights reserved.
# SPDX-License-Identifier: Proprietary
"""Azure DevOps PR comment formatting.

Formats policy evaluation results as Markdown comments for Azure DevOps PRs.
Uses the same format as GitHub/GitLab/Bitbucket for consistency.

Example:
    output = engine.evaluate_content(content, language)
    comment = format_check_comment(output, evaluation_id)
    # Post comment to PR thread
"""

from __future__ import annotations

from mergeguide.engine.reporter import EvaluationReport, Violation

# HTML marker for identifying MergeGuide comments (for idempotent updates)
COMMENT_MARKER = "<!-- mergeguide-policy-check -->"

# Severity icons
SEVERITY_ICONS = {
    "error": ":x:",  # Azure DevOps uses colon emoji syntax
    "warning": ":warning:",
    "info": ":information_source:",
}


def format_check_comment(
    report: EvaluationReport,
    evaluation_id: str | None = None,
    target_url: str | None = None,
) -> str:
    """Format evaluation results as a Markdown comment.

    Creates a formatted comment suitable for posting to Azure DevOps PR threads.
    Includes a hidden marker for identifying the comment on future updates.

    Args:
        report: Evaluation report with violations and summary.
        evaluation_id: Optional evaluation ID to include.
        target_url: Optional URL to link to for more details.

    Returns:
        Formatted Markdown string.

    Example:
        >>> comment = format_check_comment(report, "eval_123")
        >>> print(comment[:50])
        <!-- mergeguide-policy-check -->

        ## :white_check
    """
    lines = [COMMENT_MARKER, ""]

    # Header with pass/fail status
    if report.summary.passed:
        lines.append("## :white_check_mark: MergeGuide Policy Check: Passed")
    else:
        lines.append("## :x: MergeGuide Policy Check: Failed")

    lines.append("")

    # Summary counts
    summary_parts = []
    if report.summary.errors > 0:
        summary_parts.append(f"**{report.summary.errors}** error(s)")
    if report.summary.warnings > 0:
        summary_parts.append(f"**{report.summary.warnings}** warning(s)")
    if report.summary.infos > 0:
        summary_parts.append(f"**{report.summary.infos}** info(s)")

    if summary_parts:
        lines.append(f"Found {', '.join(summary_parts)}")
    else:
        lines.append("No violations found.")
    lines.append("")

    # Violations table
    if report.violations:
        lines.append("### Violations")
        lines.append("")
        lines.append("| Severity | File | Line | Rule | Message |")
        lines.append("|----------|------|------|------|---------|")

        # Sort by severity (errors first)
        severity_order = {"error": 0, "warning": 1, "info": 2}
        sorted_violations = sorted(
            report.violations,
            key=lambda v: (severity_order.get(v.severity, 3), v.file_path, v.line_no),
        )

        for violation in sorted_violations[:50]:  # Limit to avoid huge comments
            icon = SEVERITY_ICONS.get(violation.severity, ":grey_question:")
            file_path = _truncate(violation.file_path, 40)
            message = _escape_markdown(_truncate(violation.message, 60))
            rule_id = violation.rule_id or "-"

            lines.append(
                f"| {icon} {violation.severity} | `{file_path}` | {violation.line_no} | {rule_id} | {message} |"
            )

        if len(report.violations) > 50:
            lines.append("")
            lines.append(f"*...and {len(report.violations) - 50} more violations*")

        lines.append("")

    # Remediation guidance (grouped by rule)
    remediations = _get_remediations(report.violations)
    if remediations:
        lines.append("### How to Fix")
        lines.append("")
        for rule_id, (count, remediation) in remediations.items():
            lines.append(f"**{rule_id}** - {count} occurrence(s)")
            lines.append(f"> {remediation}")
            lines.append("")

    # Footer with metadata
    lines.append("---")
    footer_parts = []
    if evaluation_id:
        footer_parts.append(f"Evaluation ID: `{evaluation_id}`")
    footer_parts.append(f"Files checked: {report.summary.total_files}")
    footer_parts.append(f"Duration: {report.duration_ms}ms")

    if target_url:
        footer_parts.append(f"[View details]({target_url})")

    lines.append(f"<sub>{' | '.join(footer_parts)}</sub>")

    return "\n".join(lines)


def format_error_comment(error_message: str) -> str:
    """Format an error message as a comment.

    Used when evaluation fails due to an exception.

    Args:
        error_message: Error description.

    Returns:
        Formatted Markdown error comment.
    """
    return f"""{COMMENT_MARKER}

## :x: MergeGuide Policy Check: Error

The policy check could not be completed due to an error:

```
{error_message}
```

Please check your policy configuration or contact support if the issue persists.

---
<sub>MergeGuide Policy Check</sub>
"""


def _truncate(text: str, max_length: int) -> str:
    """Truncate text with ellipsis if too long."""
    if len(text) <= max_length:
        return text
    return text[: max_length - 3] + "..."


def _escape_markdown(text: str) -> str:
    """Escape special Markdown characters."""
    # Escape pipe characters which break tables
    return text.replace("|", "\\|").replace("\n", " ")


def _get_remediations(
    violations: list[Violation],
) -> dict[str, tuple[int, str]]:
    """Extract unique remediations grouped by rule.

    Args:
        violations: List of violations.

    Returns:
        Dict mapping rule_id to (count, remediation_text).
    """
    result: dict[str, tuple[int, str]] = {}

    for v in violations:
        if not v.remediation:
            continue

        rule_id = v.rule_id or "unknown"
        if rule_id in result:
            count, remediation = result[rule_id]
            result[rule_id] = (count + 1, remediation)
        else:
            result[rule_id] = (1, v.remediation)

    return result
