package output

import (
	"fmt"
	"io"
	"sort"
	"strings"

	"github.com/garagon/aguara/internal/scanner"
)

// MarkdownFormatter outputs findings as GitHub-flavored markdown,
// designed for GitHub Actions Job Summaries and PR comments.
type MarkdownFormatter struct{}

func (f *MarkdownFormatter) Format(w io.Writer, result *scanner.ScanResult) error {
	if len(result.Findings) == 0 {
		f.printClean(w, result)
		return nil
	}

	counts := f.countBySeverity(result.Findings)
	f.printHeader(w, result, counts)
	f.printFindingsByFile(w, result.Findings)
	f.printFooter(w, result)
	return nil
}

func (f *MarkdownFormatter) printClean(w io.Writer, result *scanner.ScanResult) {
	fmt.Fprintf(w, "## Aguara Security Scan\n\n")
	fmt.Fprintf(w, "> **Passed** · %d files · %d rules · %.2fs\n\n",
		result.FilesScanned, result.RulesLoaded, result.Duration.Seconds())
	fmt.Fprintf(w, "No security issues found.\n")
}

func (f *MarkdownFormatter) printHeader(w io.Writer, result *scanner.ScanResult, counts map[scanner.Severity]int) {
	fmt.Fprintf(w, "## Aguara Security Scan\n\n")

	// Severity badges inline
	severities := []scanner.Severity{
		scanner.SeverityCritical,
		scanner.SeverityHigh,
		scanner.SeverityMedium,
		scanner.SeverityLow,
		scanner.SeverityInfo,
	}
	var badges []string
	for _, sev := range severities {
		c := counts[sev]
		if c == 0 {
			continue
		}
		badges = append(badges, fmt.Sprintf("%s **%d %s**", severityEmoji(sev), c, strings.ToLower(sev.String())))
	}

	fmt.Fprintf(w, "> %s · `%s` · %d files · %d rules · %.2fs\n\n",
		strings.Join(badges, " &nbsp; "),
		result.Target, result.FilesScanned, result.RulesLoaded, result.Duration.Seconds())
}

func (f *MarkdownFormatter) printFindingsByFile(w io.Writer, findings []scanner.Finding) {
	grouped := groupByFile(findings)

	for _, group := range grouped {
		fmt.Fprintf(w, "### `%s`\n\n", group.filePath)

		fmt.Fprintf(w, "| Severity | Rule | Finding | Line |\n")
		fmt.Fprintf(w, "|:--------:|------|---------|-----:|\n")

		// Sort findings within file by severity (critical first), then line
		sorted := make([]scanner.Finding, len(group.findings))
		copy(sorted, group.findings)
		sort.Slice(sorted, func(i, j int) bool {
			if sorted[i].Severity != sorted[j].Severity {
				return sorted[i].Severity > sorted[j].Severity
			}
			return sorted[i].Line < sorted[j].Line
		})

		for _, finding := range sorted {
			emoji := severityEmoji(finding.Severity)
			fmt.Fprintf(w, "| %s | `%s` | %s | %d |\n",
				emoji, finding.RuleID, escapeMarkdown(finding.RuleName), finding.Line)
		}
		// Show remediation for high+ severity findings
		for _, finding := range sorted {
			if finding.Remediation != "" && finding.Severity >= scanner.SeverityHigh {
				fmt.Fprintf(w, "\n> **%s**: %s\n", finding.RuleID, escapeMarkdown(finding.Remediation))
			}
		}
		fmt.Fprintf(w, "\n")
	}
}

func (f *MarkdownFormatter) printFooter(w io.Writer, result *scanner.ScanResult) {
	fmt.Fprintf(w, "---\n\n")
	fmt.Fprintf(w, "<sub>Generated by [Aguara](https://github.com/garagon/aguara) %s — security scanner for AI agent skills and MCP servers</sub>\n", ToolVersion)
}

func (f *MarkdownFormatter) countBySeverity(findings []scanner.Finding) map[scanner.Severity]int {
	counts := map[scanner.Severity]int{}
	for _, finding := range findings {
		counts[finding.Severity]++
	}
	return counts
}

func severityEmoji(sev scanner.Severity) string {
	switch sev {
	case scanner.SeverityCritical:
		return ":red_circle:"
	case scanner.SeverityHigh:
		return ":orange_circle:"
	case scanner.SeverityMedium:
		return ":yellow_circle:"
	case scanner.SeverityLow:
		return ":blue_circle:"
	case scanner.SeverityInfo:
		return ":white_circle:"
	default:
		return ":black_circle:"
	}
}

func escapeMarkdown(s string) string {
	s = strings.ReplaceAll(s, "|", "\\|")
	s = strings.ReplaceAll(s, "<", "&lt;")
	s = strings.ReplaceAll(s, ">", "&gt;")
	return s
}
