const express = require("express");
const axios = require("axios");
const stringSimilarity = require("string-similarity");
const twilio = require("twilio");
const Faq = require("../models/faqModel");
const Context = require("../models/contextModel");
const he = require("he"); // For HTML entity decoding

const router = express.Router();

// Twilio Setup
const client = new twilio(
  process.env.TWILIO_ACCOUNT_SID,
  process.env.TWILIO_AUTH_TOKEN
);
const whatsappNumber = process.env.TWILIO_WHATSAPP_NUMBER;

// Function to find the best FAQ match
async function getBestMatch(userQueston) {
  console.log("Checking Bestmatch");
  //convert userQueston to lowercase
  userQueston = userQueston.toLowerCase();
  if (typeof userQueston !== "string" || userQueston.trim() === "") {
    console.error("Invalid user question:", userQueston);
    return null;
  }

  const faqs = await Faq.find();
  if (!faqs || faqs.length === 0) {
    console.error("No FAQs found in the database.");
    return null;
  }

  const questions = faqs.map((faq) => faq.question.toLowerCase());
  if (!Array.isArray(questions) || questions.length === 0) {
    console.error("FAQ questions are not in a valid array.");
    return null;
  }

  const bestMatch = stringSimilarity.findBestMatch(userQueston, questions);

  if (bestMatch.bestMatch.rating > 0.5) {
    console.log(
      "Best match faq found:",
      bestMatch.bestMatch.target,
      bestMatch.bestMatch.rating
    );
    return faqs.find(
      (faq) => faq.question.toLowerCase() === bestMatch.bestMatch.target
    );
  }

  return null;
}

// Function to get chatbot response using context-aware QA model
async function getChatbotResponse(message) {
  console.log("Checking the context DB.");

  const contextDoc = await Context.findOne({ content: { $exists: true } });
  if (!contextDoc) {
    console.log("No context found, falling back to web search.");
    return await fallbackWebSearch(message);
  }

  const contextText = contextDoc.content;
  const CHUNK_SIZE = 1000;

  const chunks = [];
  for (let i = 0; i < contextText.length; i += CHUNK_SIZE) {
    chunks.push(contextText.slice(i, i + CHUNK_SIZE));
  }

  let bestAnswer = "";
  let bestScore = 0;

  for (const chunk of chunks) {
    try {
      const response = await axios.post(
        "https://api-inference.huggingface.co/models/deepset/roberta-base-squad2",
        {
          inputs: {
            question: message.toLowerCase(),
            context: chunk.toLowerCase(),
          },
        },
        {
          headers: {
            Authorization: `Bearer ${process.env.HUGGINGFACE_API_KEY}`,
            "Content-Type": "application/json",
          },
        }
      );

      if (
        response.data &&
        response.data.answer &&
        response.data.score !== undefined
      ) {
        const { answer, score } = response.data;
        console.log(`Chunk score: ${score} | Answer: ${answer}`);

        if (answer.length > 1 && score > bestScore) {
          bestAnswer = answer;
          bestScore = score;
        }
      }
    } catch (error) {
      console.error("Error processing chunk:", error.message);
      continue;
    }
  }

  if (bestAnswer && bestScore > 0.01) {
    return bestAnswer.slice(0, 250);
  }

  return await fallbackWebSearch(message);
}

// Fallback to DuckDuckGo Web Search
async function fallbackWebSearch(query) {
  try {
    console.log("Now on websearch");
    const response = await axios.get("https://api.duckduckgo.com/", {
      params: {
        q: query,
        format: "json",
        no_redirect: 1,
        no_html: 1,
      },
    });

    if (response.data.AbstractText && response.data.AbstractText.length > 0) {
      let abstractText = response.data.AbstractText;
      return abstractText.length > 200
        ? abstractText.substring(0, 200) + "..."
        : abstractText;
    } else if (
      response.data.RelatedTopics &&
      response.data.RelatedTopics.length > 0
    ) {
      let topic = response.data.RelatedTopics[0];
      if (topic.Text) {
        return topic.Text.length > 250
          ? topic.Text.substring(0, 250) + "..."
          : topic.Text;
      }
    } else {
      return "I couldn't find anything relevant in my archive. Please contact the school.";
    }
  } catch (error) {
    console.error("Error fetching web search results:", error);
    return "I'm not sure. Please contact the school.";
  }
}

// Chatbot for Website
router.post("/chat", async (req, res) => {
  const { message } = req.body;
  console.log("Message received on web:", message);

  let responseText = "I'm not sure. Please contact the school.";

  const faqMatch = await getBestMatch(message);
  if (faqMatch) {
    responseText = faqMatch.answer;
  } else {
    responseText = await getChatbotResponse(message);
  }

  res.json({ reply: he.decode(responseText) });
});

// WhatsApp Chatbot
router.post("/whatsapp", async (req, res) => {
  const message = req.body.Body;
  const sender = req.body.From;

  console.log("Message received on WhatsApp:", message);
  let responseText = "I'm not sure. Please contact the school.";

  if (!message) {
    console.error("No message received!");
    return res.status(400).json({ error: "No message received" });
  }

  try {
    const faqMatch = await getBestMatch(message);
    if (faqMatch) {
      responseText = faqMatch.answer;
    } else {
      responseText = await getChatbotResponse(message);
    }

    await client.messages.create({
      from: process.env.TWILIO_WHATSAPP_NUMBER, // Your Twilio WhatsApp number
      to: sender,
      body: he.decode(responseText),
      // statusCallback: `${process.env.BACKEND_BASE_URL}/api/twilio/status`
    });

    res.json({ reply: he.decode(responseText) });
  } catch (error) {
    console.error("Error processing message:", error);
    res.status(500).json({ error: "Internal server error" });
  }
});

// Twilio Message Status Callback
router.post("/twilio/status", (req, res) => {
  const { MessageSid, MessageStatus, To, From, ErrorCode, ErrorMessage } =
    req.body;

  console.log("Twilio Status Callback Received:");
  console.log(`➤ SID: ${MessageSid}`);
  console.log(`➤ Status: ${MessageStatus}`);
  console.log(`➤ From: ${From}`);
  console.log(`➤ To: ${To}`);

  if (ErrorCode) {
    console.error(
      `⚠️ Delivery failed with ErrorCode ${ErrorCode}: ${ErrorMessage}`
    );
  }

  // Optionally store status in DB or trigger custom logic here

  res.sendStatus(200);
});

module.exports = router;
