// chat-engine.jsx — shared chat logic for all Fetch variants.
// Response pipeline: intent matching → keyword lookup → fallbacks.
// Two backends: "claude" (window.claude.complete) and "local" (intent
// matching + keyword lookup + fallbacks — the path HF Static Spaces take).

const KNOWLEDGE_BASE = [
  ["domesticate",  "Dogs have been domesticated for at least 15,000 years, making them the oldest domesticated animal."],
  ["skills",       "Dogs can understand up to 250 words and gestures, and can count up to 5."],
  ["border collie","Border Collies are considered the most intelligent dog breed, capable of learning a new command in under 5 seconds."],
  ["greyhound",    "Greyhounds can reach speeds of up to 45 mph, yet are famously calm and lazy indoors."],
  ["exercise",     "Dogs need mental stimulation as much as physical exercise. A bored dog is often a destructive dog."],
  ["dental",       "Regular dental care is one of the most overlooked aspects of dog health. Most dogs show signs of dental disease by age 3."],
  ["bark",         "The Basenji is the only dog breed that doesn't bark... it yodels."],
  ["smell",        "Dogs have a sense of smell estimated to be 10,000 to 100,000 times more acute than humans."],
  ["dream",        "Dogs dream just like humans do. Research suggests they replay their day while sleeping, and smaller breeds tend to dream more frequently than larger ones."],
  ["woof",         "Did someone say woof? You speak my language."],
  ["good boi",     "That would be me, obviously."],
  ["walk",         "Did anybody say walk? I'm in."],
  ["nose",         "A dog's nose print is unique, like a human fingerprint — no two are the same."],
  ["sleep",        "Dogs sleep 12–14 hours a day on average. Puppies and seniors can sleep up to 18 hours."],
  ["sweat",        "Dogs have sweat glands in their paws — one of the few places they actually sweat."],
  ["puppy",        "Puppies are born blind, deaf, and toothless. Their eyes and ears open at around 2–3 weeks old."],
  ["hear",         "Dogs can hear sounds four times farther away than humans and detect frequencies up to 65,000 Hz."],
  ["color",        "Dogs aren't fully colorblind — they can see blue and yellow, but not red or green."],
  ["tail",         "A dog wagging its tail to the right signals positive feelings; to the left, anxiety or stress."],
  ["golden",       "Golden Retrievers have such a soft bite they can carry a raw egg without cracking it."],
  ["poodle",       "Poodles were originally bred as water retrievers — the iconic clip was functional, not decorative."],
  ["husky",        "Huskies are among the closest living genetic relatives of the ancient grey wolf."],
];

const FALLBACKS = [
  "I don't know, but I'd bet a dog would!",
  "Good question! I need more dog facts for that one.",
  "I'm not sure about that, but dogs are great!",
];

const INTENTS = [
  {
    label: "greeting",
    patterns: [/\b(hi|hello|hey)\b/i, /good (morning|afternoon|evening)/i],
    response: "Hi! I'm Fetch Pup. Ask me something about dogs, or try the suggestions below.",
  },
  {
    label: "small talk",
    patterns: [/how are you/i, /how('s| is) it going/i, /what'?s up/i],
    response: "Tail's wagging, thanks for asking! Got a dog question for me?",
  },
  {
    label: "capability",
    patterns: [/what can you do/i, /what do you (know|do)/i, /\bhelp\b/i],
    response: "I know a bunch of dog facts. Ask a question or try the suggestions — I'll do my best.",
  },
  {
    label: "identity",
    patterns: [/who are you/i, /what are you/i],
    response: "I'm Fetch Pup — a static chatbot demo. No model running, just intent matching and keyword lookup. But I know my dogs!",
  },
];

function matchIntent(query) {
  const q = query || "";
  for (const intent of INTENTS) {
    if (intent.patterns.some(p => p.test(q))) return intent;
  }
  return null;
}

const SUGGESTIONS = [
  "Tell me about border collies",
  "How good is a dog's sense of smell?",
  "Do dogs dream?",
  "Why is dental care important?",
  "How long have dogs been domesticated?",
  "Do all dogs bark?",
  "Tell me about greyhounds",
  "How much exercise does my dog need?",
  "Are dog nose prints unique?",
  "How much do dogs sleep?",
  "Do dogs sweat?",
  "What can a newborn puppy see?",
  "How well do dogs hear?",
  "Are dogs colorblind?",
  "What does tail wagging mean?",
  "Tell me about golden retrievers",
  "Tell me about poodles",
  "Tell me about the husky breed",
];

const INITIAL_GREETING = "Hi there! Ask me something simple, ideally about dogs.";

function retrieveFact(query) {
  const q = (query || "").toLowerCase();
  for (const [keyword, fact] of KNOWLEDGE_BASE) {
    if (q.includes(keyword)) return { keyword, fact };
  }
  return null;
}

function pickFallback() {
  return FALLBACKS[Math.floor(Math.random() * FALLBACKS.length)];
}

// Build a BlenderBot-style prompt so the "claude" backend produces responses
// in the same voice the Python reference targeted.
function buildPrompt(history, userInput, fact, personality) {
  const lastFour = history.slice(-4);
  const lines = lastFour.map(m => `${m.role === "user" ? "User" : "Bot"}: ${m.content}`);
  if (fact) lines.unshift(fact.fact);
  lines.push(`User: ${userInput}`);
  const toneByLevel = {
    subtle:  "Keep the dog references light; answer the question plainly.",
    medium:  "Be warm and playful, with a clear dog-lover streak.",
    loud:    "Go full dog mode: enthusiastic, tail-wagging, lots of 'woof' energy.",
  };
  const tone = toneByLevel[personality] || toneByLevel.subtle;
  return (
    "You are Fetch, a friendly dog-loving chatbot. "
    + "Answer in 1–2 short sentences. "
    + tone + " "
    + "If a fact is provided above the conversation, weave it naturally into your reply.\n\n"
    + lines.join("\n")
    + "\nBot:"
  );
}

async function generateReply({ userInput, history, backend, personality }) {
  const intent = matchIntent(userInput);
  if (intent) return { text: intent.response, fact: null, source: "intent", label: intent.label };

  const fact = retrieveFact(userInput);

  if (backend === "claude" && typeof window !== "undefined" && window.claude?.complete) {
    try {
      const prompt = buildPrompt(history, userInput, fact, personality);
      const raw = await window.claude.complete(prompt);
      const text = (raw || "").trim().replace(/^Bot:\s*/i, "").split("\nUser:")[0].trim();
      if (!text || text.split(/\s+/).length <= 2) {
        return { text: pickFallback(), fact, source: "fallback" };
      }
      return { text, fact, source: "model" };
    } catch (err) {
      console.warn("Fetch: claude backend failed, falling back.", err);
      // fall through to local path
    }
  }

  // Local / offline / HF-static path: keyword fact wins, else fallback.
  if (fact) return { text: fact.fact, fact, source: "fact" };
  return { text: pickFallback(), fact: null, source: "fallback" };
}

// Hook: owns conversation state + send/clear + rotating suggestions.
function useFetchChat({ backend = "claude", personality = "subtle" } = {}) {
  const [messages, setMessages] = React.useState(() => [
    { id: "m0", role: "assistant", content: INITIAL_GREETING, ts: Date.now() },
  ]);
  const [pending, setPending] = React.useState(false);
  const [debug, setDebug] = React.useState([]);
  const seq = React.useRef(1);

  const nextId = () => `m${seq.current++}`;

  const send = React.useCallback(async (rawInput) => {
    const userInput = (rawInput || "").trim();
    if (!userInput || pending) return;

    const userMsg = { id: nextId(), role: "user", content: userInput, ts: Date.now() };
    const placeholderId = nextId();
    const placeholder = { id: placeholderId, role: "assistant", content: "…", pending: true, ts: Date.now() };

    // Snapshot history BEFORE adding the new user message — that's what the
    // prompt builder should see as prior context.
    let priorHistory = [];
    setMessages(prev => { priorHistory = prev; return [...prev, userMsg, placeholder]; });
    setPending(true);

    const t0 = performance.now();
    let result;
    try {
      result = await generateReply({ userInput, history: priorHistory, backend, personality });
    } catch (err) {
      console.error("Fetch: generateReply failed.", err);
      result = { text: "Something went wrong. Please try again.", fact: null, source: "error" };
    }
    const { text, fact, source, label } = result;
    const ms = Math.round(performance.now() - t0);

    setMessages(prev => prev.map(m =>
      m.id === placeholderId
        ? { ...m, content: text, pending: false, fact, ts: Date.now() }
        : m
    ));
    setDebug(prev => [
      { t: Date.now(), user: userInput, reply: text, fact, source, label, ms, backend },
      ...prev,
    ].slice(0, 20));
    setPending(false);
  }, [backend, personality, pending]);

  const reset = React.useCallback(() => {
    seq.current = 1;
    setMessages([{ id: "m0", role: "assistant", content: INITIAL_GREETING, ts: Date.now() }]);
    setDebug([]);
  }, []);

  return { messages, pending, debug, send, reset };
}

// Suggestion carousel — replaces 1 or 2 at random per tick, no duplicates.
function useRotatingSuggestions({ visible = 3, intervalMs = 6000 } = {}) {
  const [current, setCurrent] = React.useState(() =>
    [...SUGGESTIONS].sort(() => Math.random() - 0.5).slice(0, visible)
  );
  React.useEffect(() => {
    const id = setInterval(() => {
      setCurrent(prev => {
        const available = SUGGESTIONS.filter(s => !prev.includes(s));
        const count = Math.random() < 0.5 ? 1 : 2;
        const incoming = [...available].sort(() => Math.random() - 0.5).slice(0, count);
        const slots = [...Array(visible).keys()].sort(() => Math.random() - 0.5).slice(0, count);
        const next = [...prev];
        slots.forEach((slot, i) => { next[slot] = incoming[i]; });
        return next;
      });
    }, intervalMs);
    return () => clearInterval(id);
  }, [visible, intervalMs]);
  return current;
}

Object.assign(window, {
  useFetchChat,
  useRotatingSuggestions,
  retrieveFact,
  FETCH_KNOWLEDGE_BASE: KNOWLEDGE_BASE,
  FETCH_SUGGESTIONS: SUGGESTIONS,
  FETCH_INTENTS: INTENTS,
});
