import {
  Alert, Autocomplete, Button, Code, Divider, Group, Paper, Stack, Text, Textarea, TextInput, Tooltip,
} from "@mantine/core";
import { useForm } from "@mantine/form";
import { IconAlertCircle, IconLock } from "@tabler/icons-react";
import { useMemo, useState } from "react";
import { useNavigate } from "react-router";
import { promptInitialValues, promptValidate } from "./prompt.form";
import type { PromptFormValues } from "./prompt.types";

// Variables available per pipeline key — shown as hints in the form
// 15 pipeline keys: 11 prompt templates + 4 JSON config objects — all must be set in the admin panel
const KEY_VARIABLE_HINTS: Record<string, { vars: string[]; note?: string }> = {
  // ── Core AI prompts (required) ────────────────────────────────────────────
  system_prompt: {
    vars: ["{context}", "{user_query}", "{name}", "{email}", "{login_status}", "{active_resort}", "{links_from_excel}", "{current_date}", "{current_time}", "{context_summary}"],
  },
  memory_prompt: {
    vars: ["{current_message}", "{known_name}", "{known_email}", "{context_summary}", "{recent_history}", "{active_resort}", "{pending_question}", "{pending_slot}", "{assistant_intent}"],
  },
  routing_resolver_prompt: {
    vars: ["{message}", "{agents}", "{active_resort}", "{suggested_resort}", "{last_successful_query}", "{last_user_message}", "{last_bot_message}", "{context_summary}", "{resorts}", "{countries}", "{states}"],
    note: "Single LLM call that handles both agent routing and query resolution. Must return JSON only: {\"domain\": \"category_key_or_empty\", \"mode\": \"exact_resort|destination_browse|follow_up|general\", \"resolved_resort\": \"exact name or empty\", \"resolved_destination\": \"country/region or empty\", \"reason\": \"one sentence\"}.",
  },
  bad_response_retry_prompt: {
    vars: ["{context_text}", "{recent_history_text}", "{resort_hint}", "{topic_hint}"],
    note: "Fires when the model returns a response matching a bad_response_markers phrase. Redirect the model back to a helpful answer.",
  },
  answer_generation_instructions: {
    vars: [],
    note: "Appended after the full rendered prompt. Use for strict output format rules e.g. 'Output ONLY valid HTML wrapped in <div>...</div>'.",
  },
  context_summary_prompt: {
    vars: ["{previous_summary}", "{new_messages}"],
    note: "Called when conversation history exceeds the max length. Compress old turns into a rolling summary.",
  },
  // ── Feature prompts ────────────────────────────────────────────────────────
  rephrase_prompt: {
    vars: ["{instruction}", "{user_context}"],
    note: "Polishes the memory-stage AI response before showing to the user. {instruction} = task instruction string, {user_context} = JSON of current user data.",
  },
  memory_stage_instructions: {
    vars: [],
    note: "JSON format rules injected into the memory stage prompt. Must instruct the model to return a valid JSON object with: name, email, active_resort, pending_question, assistant_intent, memory_sufficient.",
  },
  answer_verification_prompt: {
    vars: ["{query}", "{response_text}", "{context_text}"],
    note: "Must return YES or NO. YES = response is grounded in context. Runs when ENABLE_ANSWER_VERIFICATION is on for the agent and a verification_trigger phrase is found in the response.",
  },
  crawl_decision_prompt: {
    vars: ["{message}"],
    note: "Decides whether the user's message needs a live web crawl. Must return JSON: {\"action\": \"crawl_website\", \"parameters\": {\"target\": \"...\", \"is_url\": true/false}} or {\"action\": \"none\"}. Web crawling is enabled/disabled via crawl_enabled in runtime_config.",
  },
  intent_classification_prompt: {
    vars: ["{message}", "{context}"],
    note: "Classifies the user's intent during onboarding. Must return one of: ask_name, ask_email, retry_name, invalid_email, welcome_back, onboarding_complete, general.",
  },
  // ── JSON config objects ───────────────────────────────────────────────────
  runtime_config: {
    vars: [],
    note: `JSON object controlling session sizing, token budgets, and feature toggles. All fields are optional — defaults are used when omitted.
Example:
{
  "max_history_messages": 120,
  "max_context_summary_chars": 24000,
  "max_recent_history_messages": 20,
  "max_history_message_chars": 1200,
  "max_context_message_chars": 800,
  "max_current_message_chars": 1600,
  "short_reply_max_chars": 80,
  "promote_query_min_chars": 24,
  "allow_context_summary": true,
  "session_recovery_hours": 2,
  "crawl_enabled": true,
  "memory_stage_enabled": true
}`,
  },
  retrieval_config: {
    vars: [],
    note: `JSON object controlling RAG chunk retrieval tuning. All fields optional.
Example:
{
  "min_score": 15.0,
  "mmr_lambda": 0.65,
  "top_n": {"exact_resort": 6, "follow_up": 5, "destination_browse": 12, "general": 8},
  "summary_caps": {"exact_resort": 4000, "follow_up": 6000, "destination_browse": 10000, "general": 16000},
  "history_limits": {"exact_resort": 5, "follow_up": 8, "destination_browse": 10, "general": 15}
}`,
  },
  chat_messages: {
    vars: [],
    note: `JSON object for all user-facing static text and HTML fallbacks. All fields optional.
Example:
{
  "first_message": "Hi! How can I help you today?",
  "recovery_prompt": "Welcome back! Would you like to continue your previous chat or start fresh?",
  "session_not_found": "Sorry, I couldn't find your previous session.",
  "resuming_session": "Resuming your previous session...",
  "default_user_name": "Guest",
  "soft_fallback_html": "<div><p>I'm sorry, I don't have that information right now.</p></div>",
  "no_context_text": "No specific information found in our knowledge base.",
  "strict_unavailable": "This information is not available through our chatbot.",
  "weak_response_fallback": "Let me try to find a better answer for you.",
  "prompt_merge_connector": "",
  "context_block_header": "IMPORTANT: Use only the following following verified information to answer.",
  "context_block_footer": "--- END OF CONTEXT ---"
}`,
  },
  filter_config: {
    vars: [],
    note: `JSON object for phrase lists used by the response quality pipeline. All fields optional — empty list = feature disabled.
Example:
{
  "bad_response_markers": ["I don't have information", "I cannot provide", "I'm unable to"],
  "response_cleanup_phrases": ["As an AI language model", "I hope this helps!"],
  "verification_triggers": ["price", "rate", "available", "booking", "cost"]
}`,
  },
};

// Generic variables shown when no pipeline key is selected
const GENERIC_VARS = ["{context}", "{user_query}", "{name}", "{login_status}", "{active_resort}", "{links_from_excel}"];

const ALL_PIPELINE_KEYS = [
  // Core AI prompts — required for the bot to function
  { value: "system_prompt",               label: "system_prompt — Main assistant persona & rules" },
  { value: "memory_prompt",               label: "memory_prompt — Conversation memory & identity" },
  { value: "routing_resolver_prompt",     label: "routing_resolver_prompt — Agent routing + query resolution (single LLM call)" },
  { value: "bad_response_retry_prompt",   label: "bad_response_retry_prompt — Retry prompt when model gives a bad response" },
  { value: "answer_generation_instructions", label: "answer_generation_instructions — Output format rules appended to every prompt" },
  { value: "context_summary_prompt",      label: "context_summary_prompt — Compresses long conversation history into a rolling summary" },
  // Feature prompts
  { value: "rephrase_prompt",              label: "rephrase_prompt — Polishes memory-stage responses before showing to user" },
  { value: "memory_stage_instructions",    label: "memory_stage_instructions — JSON format rules for the memory extraction stage" },
  { value: "answer_verification_prompt",   label: "answer_verification_prompt — Verifies answer is grounded in context (YES/NO)" },
  { value: "crawl_decision_prompt",        label: "crawl_decision_prompt — Decides whether user message needs a live web crawl" },
  { value: "intent_classification_prompt", label: "intent_classification_prompt — Classifies guest intent during onboarding flow" },
  // JSON config objects — paste a JSON object as the prompt value
  { value: "runtime_config",              label: "runtime_config — JSON: session sizing, token budgets, crawl_enabled, memory_stage_enabled" },
  { value: "retrieval_config",            label: "retrieval_config — JSON: RAG tuning (min_score, mmr_lambda, top_n, summary_caps, history_limits)" },
  { value: "chat_messages",               label: "chat_messages — JSON: all user-facing text, fallback HTML, and chat flow messages" },
  { value: "filter_config",               label: "filter_config — JSON: bad_response_markers, response_cleanup_phrases, verification_triggers" },
  // Note: voice_character_prompt and voice_tts_config are managed exclusively via the Voice Prompts tab
];


export default function PromptForm({
  mode,
  initial,
  usedPipelineKeys = [],
  onSubmit,
}: {
  mode: "create" | "edit";
  initial?: Partial<PromptFormValues>;
  usedPipelineKeys?: string[];
  onSubmit: (payload: { prompt_name: string; prompt_value: string; prompt_key: string }) => Promise<any>;
}) {
  const navigate = useNavigate();
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const form = useForm<PromptFormValues>({
    initialValues: promptInitialValues(initial),
    validate: promptValidate,
    validateInputOnBlur: true,
  });

  // True when editing a prompt that already has a pipeline key — key is locked forever
  const isPipelineKeyLocked = mode === "edit" && !!initial?.prompt_key?.trim();

  const currentKey = initial?.prompt_key ?? "";
  const keySuggestions = useMemo(() => {
    const predefined = new Set(ALL_PIPELINE_KEYS.map((opt) => opt.value));
    // Available predefined pipeline keys (not taken by another prompt)
    const availablePredefined = ALL_PIPELINE_KEYS.map((opt) => opt.value).filter(
      (v) => !usedPipelineKeys.includes(v) || v === currentKey,
    );
    // Custom keys created by admins that aren't in the predefined list
    const customKeys = usedPipelineKeys.filter((k) => k && !predefined.has(k));
    return [...availablePredefined, ...customKeys];
  }, [usedPipelineKeys, currentKey]);

  const selectedKey = form.values.prompt_key ?? "";
  const keyHint = selectedKey ? KEY_VARIABLE_HINTS[selectedKey] : null;
  const varsToShow = keyHint ? keyHint.vars : GENERIC_VARS;

  const handleSave = async (values: PromptFormValues) => {
    setError(null);
    setSaving(true);
    const payload = {
      prompt_name: values.prompt_name.trim(),
      prompt_value: values.prompt_value.trim(),
      prompt_key: values.prompt_key?.trim() || "",
    };
    try {
      await onSubmit(payload);
      navigate(-1);
    } catch (e: any) {
      setError(e?.message || `Failed to ${mode === "create" ? "create" : "update"} prompt.`);
    } finally {
      setSaving(false);
    }
  };

  return (
    <Paper withBorder p="lg" radius="md" maw={860}>
      <form onSubmit={form.onSubmit(handleSave)}>
        <Stack gap="md">
          <Group justify="space-between">
            <Text fw={600} size="lg">{mode === "create" ? "Create Prompt" : "Edit Prompt"}</Text>
            <Group gap="xs">
              <Button variant="subtle" color="gray" onClick={() => navigate(-1)} disabled={saving}>
                Cancel
              </Button>
              <Button type="submit" loading={saving} disabled={!form.isValid() || saving}>
                {mode === "create" ? "Save Prompt" : "Update Prompt"}
              </Button>
            </Group>
          </Group>

          <Divider label="Prompt Details" />

          <TextInput
            label="Prompt Name"
            description="Short label to identify this prompt (e.g. 'Accommodation Agent Prompt')"
            placeholder="My Prompt"
            required
            error={form.errors.prompt_name}
            {...form.getInputProps("prompt_name")}
          />

          <Autocomplete
            label="Pipeline Key"
            description={
              <Stack gap={2} mt={2}>
                {isPipelineKeyLocked ? (
                  <Text size="xs" c="orange.6" fw={500}>
                    Pipeline key is locked after creation and cannot be changed.
                  </Text>
                ) : (
                  <Text size="xs" c="dimmed">
                    Leave blank for agent prompts — agents follow category-based routing and do not need a pipeline key.
                    Set a key only if this prompt handles a <strong>code-level pipeline task</strong> (e.g.{" "}
                    <Code fz="xs">system_prompt</Code>, <Code fz="xs">routing_resolver_prompt</Code>).
                    Type any custom key or pick from suggestions. Each key can only be assigned to one prompt.
                  </Text>
                )}
              </Stack>
            }
            placeholder={isPipelineKeyLocked ? "" : "Leave blank for agent prompts, or type a pipeline key"}
            disabled={isPipelineKeyLocked}
            data={keySuggestions}
            rightSection={
              isPipelineKeyLocked ? (
                <Tooltip label="Pipeline key cannot be changed after creation" withArrow>
                  <IconLock size={14} style={{ color: "var(--mantine-color-orange-6)" }} />
                </Tooltip>
              ) : undefined
            }
            error={form.errors.prompt_key}
            {...form.getInputProps("prompt_key")}
          />

          <Textarea
            label="Prompt Text"
            description={
              <Stack gap={4} mt={2}>
                {keyHint?.note && (
                  <Text size="xs" c="blue.6" fw={500}>
                    {keyHint.note}
                  </Text>
                )}
                {varsToShow.length > 0 ? (
                  <Text size="xs" c="dimmed">
                    Available variables:{" "}
                    {varsToShow.map((v, i) => (
                      <span key={v}>
                        <Code fz="xs">{v}</Code>
                        {i < varsToShow.length - 1 ? " " : ""}
                      </span>
                    ))}
                  </Text>
                ) : (
                  !keyHint?.note && (
                    <Text size="xs" c="dimmed">No template variables for this key.</Text>
                  )
                )}
              </Stack>
            }
            placeholder="You are Karma AI..."
            required
            autosize
            minRows={8}
            maxRows={24}
            error={form.errors.prompt_value}
            {...form.getInputProps("prompt_value")}
          />

          {error && (
            <Alert color="red" icon={<IconAlertCircle />} title="Error">
              {error}
            </Alert>
          )}
        </Stack>
      </form>
    </Paper>
  );
}
