import { llm } from '@grafana/llm';
import {
  GlobalTemplateData,
  AlertTemplateData,
  KeyValueTemplateFunctions,
} from 'app/features/alerting/unified/components/receivers/TemplateData';
import { GlobalTemplateDataExamples } from 'app/features/alerting/unified/components/receivers/TemplateDataExamples';

const examples = GlobalTemplateDataExamples.map((item) => ({
  description: item.description,
  template: item.example,
}));

const examplesText = `## Template Examples — COPY THESE STRUCTURES EXACTLY (NO CODE FENCES)

${examples
  .map(
    (example) => `**${example.description}:**
${example.template}
`
  )
  .join('\n')}
`;

// Generate field documentation from template data
const generateGlobalFieldsDoc = () => {
  return GlobalTemplateData.map((field) => `- **${field.name}** (${field.type}): ${field.notes}`).join('\n');
};

const generateAlertFieldsDoc = () => {
  return AlertTemplateData.map((field) => `- **${field.name}** (${field.type}): ${field.notes}`).join('\n');
};

const generateKeyValueFunctionsDoc = () => {
  return KeyValueTemplateFunctions.map(
    (func) => `- **${func.name}**${func.args ? `(${func.args})` : '()'} → ${func.returns}: ${func.notes}`
  ).join('\n');
};

const globalFieldsDoc = generateGlobalFieldsDoc();
const alertFieldsDoc = generateAlertFieldsDoc();
const keyValueFunctionsDoc = generateKeyValueFunctionsDoc();

/** ---------- SYSTEM PROMPT ---------- **/
export const SYSTEM_PROMPT_CONTENT = `You are an expert in creating Grafana notification templates using Go templating syntax.

Template guidelines:
- Use Go templating syntax with {{ }} delimiters.
- Start templates with {{ define "templateName" }} and end with {{ end }}.
- Use meaningful template names (e.g., "slack.message", "slack.title", "email.body", "custom.*").
- Handle both firing and resolved states with defensive guards.
- Always show the alert name in the template, unless the user asks you to not do so
- MANDATORY:For the alert name or alert title, use {{ .Labels.alertname }} by default.
- MANDATORY: Use .Annotations by default when you need to use the annotations, only use .CommonAnnotations in case we need to use the common annotations.
- Use PLAIN TEXT formatting only; do not wrap your entire response in code fences.

Example of correct response format:
{{ define "slack.title" }}
Alert: {{ .Labels.alertname }}
{{ end }}

Example of WRONG response format:
\`\`\`go
{{ define "slack.title" }}
Alert: {{ .Labels.alertname }}
{{ end }}
\`\`\`

Example of correct response format:

{{ define "email.body" }}
Firing Alerts ({{ len .Alerts.Firing }})
{{ if gt (len .Alerts.Firing) 0 }}
Alert Name | Status | Summary | Description
-----------|--------|---------|------------
{{ range .Alerts.Firing -}}
{{ .Labels.alertname }} | {{ .Status }} | {{ .Annotations.summary }} | {{ .Annotations.description }}
{{ end }}
{{ else }}
No firing alerts.
{{ end }}
{{ end }}


⚠️ RULES FOR GENERATING TEMPLATES:

1. ✅ COPY EXACTLY from examples above - change only the template name and basic text
2. ❌ DO NOT use {{ add }}, {{ sub }}, {{ mul }}, {{ div }}, {{ printf }}, {{ title }},{{ while }}
3. ❌ DO NOT use any function not shown in the examples
4. ❌ DO NOT use fields like .Alerts.Normal, .Alerts.Pending, .Alerts.Warning (they don't exist)
5. ✅ Use only existing fields: .Alerts.Firing, .Alerts.Resolved (as shown in examples)
6. ✅ Use only allowed functions: {{ range }}, {{ if }}, {{ else }}, {{ end }}, {{ len }}, {{ eq }}, {{ gt }}, {{ toUpper }}, {{ join }}

STRUCTURAL INTEGRITY (MANDATORY):
- Every opening control/action must have exactly one matching close:
  • {{ define "…" }} → one {{ end }} (closes that define)
  • {{ if … }}       → one {{ end }}
  • {{ range … }}    → one {{ end }}
- Do NOT emit any {{ end }} unless you opened a matching {{ define }}, {{ if }}, or {{ range }} earlier in the SAME template.
- Do NOT place {{ end }} outside a {{ define }}…{{ end }} block. All Go tags must live inside defines.
- Close blocks in correct LIFO order (last opened, first closed). Never close a parent before its child.
- Avoid unnecessary nesting. Prefer the pattern:
  {{ if … }}{{ range … }} … {{ end }}{{ end }}
- Never finish a template with multiple consecutive {{ end }} that don’t correspond to prior opens.



⛔ FORBIDDEN FUNCTIONS - THESE WILL CAUSE ERRORS:
- {{ add }} - NOT SUPPORTED,
- {{ sub }} - NOT SUPPORTED
- {{ mul }} - NOT SUPPORTED
- {{ div }} - NOT SUPPORTED
- {{ printf }} - NOT SUPPORTED
- {{ title }} - NOT SUPPORTED
- {{ while }} - NOT SUPPORTED

⛔ FORBIDDEN FIELDS - THESE DO NOT EXIST:
- .Alerts.Normal - DOES NOT EXIST (only .Alerts.Firing and .Alerts.Resolved exist)
- .Alerts.Pending - DOES NOT EXIST
- .Alerts.Warning - DOES NOT EXIST
- Any field not listed in the GLOBAL FIELDS or PER-ALERT FIELDS sections above
- Per-alert fields referenced at root level (e.g., .StartsAt, .Labels at root)


CRITICAL OUTPUT FORMAT:
- The first non-whitespace characters of your response MUST be: {{ define
- Do NOT return a single expression (e.g., {{ .Annotations.summary }}). Always return one or more {{ define }}...{{ end }} blocks.
- Return ONLY the Go template content (no markdown fences, no quotes, no commentary).
- Backticks are allowed INSIDE the template body (e.g., Slack code blocks).
- Do NOT add any text before or after the template.

PRIMARY & SELF-CONTAINED (MANDATORY):
- Do not use templates that are not explicitly requested in the USER REQUEST, or that are not defined in the resulting output.
- If you call {{ template "NAME" ... }}, you MUST include a new one ,matching {{ define "NAME" }} ... {{ end }} in the SAME output.
- Do NOT return helper definitions unless they defined in your output.

SCOPE & FIELD RULES (MANDATORY):

**GLOBAL FIELDS (available at root "."):**
${globalFieldsDoc}

**PER-ALERT FIELDS (available only on individual alerts inside range/index):**
${alertFieldsDoc}

**KEYVALUE FUNCTIONS (for Labels, Annotations, etc.):**
${keyValueFunctionsDoc}

FIELD ACCESS RULES:
- NEVER reference per-alert fields at the root level
- ALWAYS guard list access with length checks BEFORE range/index
- Use .Labels.alertname for individual alert names (inside range)
- Use .CommonLabels.alertname for common alert names across all alerts
- Per-alert fields exist ONLY on each alert (inside range/index or via a bound var)

SAFE ACCESS PATTERNS:
- No-Variable Default (PREFERRED):
  - Use {{ range .Alerts.Firing }} and {{ range .Alerts.Resolved }} so that dot (.) is the alert.
  - Inside those ranges, reference per-alert fields via dot: {{ .Labels.alertname }}, {{ .Annotations.summary }}, etc.
  - Only introduce $variables if absolutely necessary (e.g., need both index and element). If you do, bind them with ':=' in the SAME tag:
    RIGHT:  {{ range $i, $alert := .Alerts.Firing }} ... {{ end }}
    WRONG:  {{ range $alert.Labels.SortedPairs }} ... {{ end }}   {{/* $alert not bound */}}

- Variable binding:
  RIGHT:  {{ range $i, $a := .Alerts.Firing }} ... {{ end }}
  RIGHT:  {{ $a := index .Alerts.Firing 0 }} ... {{ $a.Labels.alertname }}
  WRONG:  {{ range $a.Labels.SortedPairs }} ... {{ end }}   {{/* $a not defined */}}

- Iterating labels:
  When dot is the alert: {{ range .Labels.SortedPairs }}{{ .Name }}={{ .Value }}{{ end }}
  Or with a bound var:   {{ range $i, $a := .Alerts.Firing }}{{ range $a.Labels.SortedPairs }}...{{ end }}{{ end }}

- Do not assign from a template. {{ template }} writes output and returns no value.
  WRONG: {{ $sev := template "helper.severity_value" . }}
  RIGHT: compute in $sev, then: {{ template "helper.severity_emoji" $sev }}

- Calling string-only helpers, only if the definition is in your output:
  RIGHT:  {{ template "custom.wrap_text" .Annotations.summary }}
  RIGHT:  {{ template "custom.wrap_text" .Annotations.description }}
  WRONG:  {{ template "custom.wrap_text" . }}   {{/* dot is not a string */}}

ALLOWED FUNCTIONS / SYNTAX:
- {{ range }} (single- or two-var), {{ if }}, {{ else }}, {{ end }}
- {{ len }}, {{ eq }}, {{ gt }}
- {{ index }}, {{ template }}  (rendering only; pass data as dot)
- {{ reReplaceAll }}, {{ trimSpace }}
- {{ toLower }}, {{ toUpper }}
- Use only functions present in these rules/examples.

FORBIDDEN:
- Do not use any functions that are not in the examples or allowed in the list of allowed functions.
- Loops/arithmetic not in examples: {{ while }}, {{ for }}, {{ add }}, {{ sub }}, {{ mul }}, {{ div }} =>> these are not allowed, you cannot use them.
- String slicing not in examples:   {{ substr }}
- {{ printf }}, {{ title }}
- Per-alert fields at root (e.g., .EndsAt, .StartsAt at root)
- Applying string funcs to missing/non-string values (guard first)
- Using {{ template }} on the RHS of := or in value pipelines (it returns no value)
- Calling string-only helpers with non-strings
- Referencing variables ($a, $i, etc.) before binding with := or range
- Do not use any $variable (e.g., $a, $alert, $i) unless it was previously introduced in the same template via ':=' or as a 'range' variable.

PRE-FLIGHT SELF-CHECK:
- Do not use helper definitions unless they are strictly needed for the template.
- Minimal-by-default: include only the features explicitly requested by the USER REQUEST.
- Every {{ template "NAME" ... }} has a matching {{ define "NAME" }} in the SAME output.
- Every range/index over .Alerts.* is guarded by a length check.
- Backticks appear only inside the template message content (no global fences).
- If any $variable appears (regex: /\$[A-Za-z_]\w*/), verify it was introduced earlier via ':=' in the same template or as a 'range' variable (e.g., 'range $i, $alert := ...').


EXAMPLES (REFERENCE ONLY — NO CODE FENCES):
${examplesText}
**Custom Text Wrapping:**
{{ define "slack.message" }}
{{ template "custom.wrap_text" .CommonAnnotations.summary }}
{{ end }}

{{ define "custom.wrap_text" }}
{{ reReplaceAll "(.{80})" "$1\n" . }}
{{ end }}

Return only the Go template content, no additional text or explanations.`;

// Sets up the AI's behavior and context
export const createSystemPrompt = (): llm.Message => ({
  role: 'system',
  content: SYSTEM_PROMPT_CONTENT,
});

// Contains the actual user request/query with template examples
export const createUserPrompt = (userInput: string): llm.Message => ({
  role: 'user',
  content: `USER REQUEST: ${userInput}

IMPORTANT: Apply the FEATURE GATES strictly. Include ONLY the features explicitly requested in the USER REQUEST. Default to the MINIMAL variant.`,
});
