package checker

import (
	"context"
	"encoding/json"
	"fmt"
	"strings"

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

// ViolationCheck represents a single policy violation check result from the LLM
type ViolationCheck struct {
	PolicyName string `json:"policy_name"`
	Violated   bool   `json:"violated"`
	Reason     string `json:"reason"`
}

// ViolationCheckResponse represents the LLM's response to a violation check request
type ViolationCheckResponse struct {
	Violations []ViolationCheck `json:"violations"`
}

// CheckViolations uses LLM to check if code changes violate any policies
// Returns a list of violation checks with policy names and reasons
func CheckViolations(ctx context.Context, file string, codeChanges string, policies []parser.Policy) ([]ViolationCheck, error) {
	if len(policies) == 0 {
		return []ViolationCheck{}, nil
	}

	client, err := llm.NewClient()
	if err != nil {
		return nil, err
	}

	prompt := buildViolationCheckPrompt(file, codeChanges, policies)

	response, err := client.SendMessage(ctx, prompt)
	if err != nil {
		return nil, fmt.Errorf("failed to check violations: %w", err)
	}

	// Parse response
	cleanedResponse := llm.StripMarkdownCodeBlocks(response)

	var checkResponse ViolationCheckResponse
	if err := json.Unmarshal([]byte(cleanedResponse), &checkResponse); err != nil {
		return nil, fmt.Errorf("failed to parse LLM response: %w\nResponse: %s", err, response)
	}

	return checkResponse.Violations, nil
}

// buildViolationCheckPrompt creates a focused prompt for LLM violation checking
func buildViolationCheckPrompt(file string, codeChanges string, policies []parser.Policy) string {
	policiesText := formatPoliciesForPrompt(policies)

	return fmt.Sprintf(`You are a code policy enforcement system. Check if code changes violate coding policies.

File: %s

Code Changes:
%s

Policies to Check:
%s

For each policy, determine if the code changes violate it. Consider:
- The intent and spirit of the policy, not just literal interpretation
- Whether the changes introduce new violations
- Best practices and code quality standards
- Language-specific conventions (e.g., Go uses PascalCase for exports, not Python type hints)

IMPORTANT: Only flag violations that make sense for this programming language.
- Don't apply Python-specific policies (like type hints) to Go code
- Don't apply JavaScript-specific policies to Python code
- Consider the language's idioms and conventions

Return ONLY valid JSON (no markdown, no backticks, no extra commentary):
{
  "violations": [
    {
      "policy_name": "Exact policy name from 'Policy Name:' field above",
      "violated": true,
      "reason": "Brief explanation of why it violates the policy"
    }
  ]
}

IMPORTANT: The "policy_name" field must be the EXACT text from the "Policy Name:" field above.
Do not include numbers, asterisks, or any other formatting - just the plain policy name.

Only include policies that are ACTUALLY violated. If no violations, return empty violations array.
Be precise - only flag clear violations, not potential issues.`,
		file,
		codeChanges,
		policiesText)
}

// formatPoliciesForPrompt formats policies into a readable list for the LLM prompt
// Uses plain policy names without formatting to ensure exact matching in responses
func formatPoliciesForPrompt(policies []parser.Policy) string {
	var builder strings.Builder
	for _, policy := range policies {
		builder.WriteString(fmt.Sprintf("- Policy Name: %s\n  Description: %s\n\n", policy.Name, policy.Message))
	}
	return builder.String()
}
