package checker

import (
	"context"
	"fmt"
	"sort"
	"strings"

	"github.com/tanagram/cli/git"
	"github.com/tanagram/cli/parser"
)

// Violation represents a policy violation found in code
type Violation struct {
	File       string
	LineNumber int
	PolicyName string
	Message    string
	Code       string
}

// CheckResult contains all violations found
type CheckResult struct {
	Violations   []Violation
	TotalChecked int
}

// CheckChanges checks all changed lines against policies using LLM-based detection
func CheckChanges(ctx context.Context, changes []git.ChangedLine, policies []parser.Policy) *CheckResult {
	result := &CheckResult{
		Violations:   []Violation{},
		TotalChecked: len(changes),
	}

	// Use LLM-based checking for all policies
	llmViolations := CheckChangesWithLLM(ctx, changes, policies)
	result.Violations = append(result.Violations, llmViolations...)

	return result
}

// FormatViolations formats violations for terminal output
func FormatViolations(result *CheckResult) string {
	if len(result.Violations) == 0 {
		return "✓ No policy violations found"
	}

	// ANSI color codes
	const (
		colorReset = "\033[0m"
		colorGray  = "\033[90m"
	)

	// Group violations by file
	violationsByFile := make(map[string][]Violation)
	for _, v := range result.Violations {
		violationsByFile[v.File] = append(violationsByFile[v.File], v)
	}

	// Sort files for consistent output
	files := make([]string, 0, len(violationsByFile))
	for file := range violationsByFile {
		files = append(files, file)
	}
	sort.Strings(files)

	var output strings.Builder
	output.WriteString(fmt.Sprintf("✗ Found %d policy violation(s):\n\n", len(result.Violations)))

	for _, file := range files {
		violations := violationsByFile[file]

		// Sort violations by line number
		sort.Slice(violations, func(i, j int) bool {
			return violations[i].LineNumber < violations[j].LineNumber
		})

		output.WriteString(fmt.Sprintf("- %s\n\n", file))

		for _, v := range violations {
			// Print the code line in gray
			output.WriteString(fmt.Sprintf("  %s%d: %s%s\n", colorGray, v.LineNumber, v.Code, colorReset))

			// Print the violation message indented with arrow
			output.WriteString(fmt.Sprintf("      ^ %s\n", v.Message))
		}
		output.WriteString("\n")
	}

	return output.String()
}

// FormatClaudeInstructions formats violations as actionable instructions for Claude Code
// to automatically fix via exit code 2 hook behavior
func FormatClaudeInstructions(result *CheckResult) string {
	if len(result.Violations) == 0 {
		return ""
	}

	// Group violations by file
	violationsByFile := make(map[string][]Violation)
	for _, v := range result.Violations {
		violationsByFile[v.File] = append(violationsByFile[v.File], v)
	}

	// Sort files for consistent output
	files := make([]string, 0, len(violationsByFile))
	for file := range violationsByFile {
		files = append(files, file)
	}
	sort.Strings(files)

	var output strings.Builder
	output.WriteString("POLICY VIOLATIONS DETECTED - PLEASE FIX\n\n")
	output.WriteString(fmt.Sprintf("Found %d policy violation(s) that need to be fixed:\n\n", len(result.Violations)))

	for _, file := range files {
		violations := violationsByFile[file]

		// Sort violations by line number
		sort.Slice(violations, func(i, j int) bool {
			return violations[i].LineNumber < violations[j].LineNumber
		})

		output.WriteString(fmt.Sprintf("File: %s\n", file))

		for _, v := range violations {
			output.WriteString(fmt.Sprintf("\n  Line %d:\n", v.LineNumber))
			output.WriteString(fmt.Sprintf("    Code: %s\n", v.Code))
			output.WriteString(fmt.Sprintf("    Policy: %s\n", v.PolicyName))
			output.WriteString(fmt.Sprintf("    Issue: %s\n", v.Message))
			output.WriteString(fmt.Sprintf("    Action: Review and fix this code to comply with the policy.\n"))
		}
		output.WriteString("\n")
	}

	output.WriteString("Please fix all violations listed above and ensure the code complies with all policies.\n")

	return output.String()
}
