import { NextRequest } from "next/server";
import { handleTextMessage, isBotCommand } from "@/lib/bot/handlers/text";
import { handleImageMessage } from "@/lib/bot/handlers/image";
import { handleButtonReply, handleInteractiveTextReply } from "@/lib/bot/handlers/interactive";
import { getSession } from "@/lib/bot/sessions";

const WEBHOOK_SECRET = (process.env.BOT_WEBHOOK_SECRET ?? "").trim();
const GROUP_JID = (process.env.WHATSAPP_GROUP_JID ?? "").trim();

// Evolution API verification token (GET)
export async function GET(req: NextRequest) {
  const { searchParams } = new URL(req.url);
  const token = searchParams.get("token");
  if (token && token === WEBHOOK_SECRET) {
    return new Response(token, { status: 200 });
  }
  return new Response("Forbidden", { status: 403 });
}

export async function POST(req: NextRequest) {
  // Verify secret
  const apikey = req.headers.get("apikey") ?? req.headers.get("x-api-key") ?? "";
  if (WEBHOOK_SECRET && apikey !== WEBHOOK_SECRET) {
    return new Response("Forbidden", { status: 403 });
  }

  let body: unknown;
  try {
    body = await req.json();
  } catch {
    return new Response("Bad Request", { status: 400 });
  }

  // Process synchronously — Vercel kills the function after response is sent
  try {
    await processWebhook(body as WebhookPayload);
  } catch (err) {
    console.error("Webhook processing error:", err);
  }

  return new Response("OK", { status: 200 });
}

// ── Types ────────────────────────────────────────────────────────────────────

interface WebhookPayload {
  event: string;
  instance: string;
  data: MessageData;
}

interface MessageData {
  key: {
    remoteJid: string;
    fromMe: boolean;
    id: string;
    participant?: string;
  };
  pushName?: string;
  message?: {
    conversation?: string;
    extendedTextMessage?: { text: string; contextInfo?: { mentionedJid?: string[] } };
    imageMessage?: { mimetype?: string; caption?: string };
    documentMessage?: { mimetype?: string; fileName?: string };
    buttonsResponseMessage?: { selectedButtonId: string; selectedDisplayText: string };
    listResponseMessage?: { singleSelectReply?: { selectedRowId: string } };
  };
  messageType?: string;
}

// ── Allowed senders ───────────────────────────────────────────────────────────
// Only these phone numbers (without country code +, without @s.whatsapp.net) can trigger the bot.
// The mapped name is passed to the AI so it can address each person correctly.

const ALLOWED_SENDERS: Record<string, string> = {
  "173104512892995": "Nacho",
  "41841823088688": "Nacho",
  "112974970794216": "Luli",
  "5491167336646": "Luli",
  "5491144378344": "Gloria",
  "5491158215174": "Nacho",
};

function parseSenders(raw: string): Record<string, string> {
  if (!raw.trim()) return ALLOWED_SENDERS;
  const result: Record<string, string> = {};
  for (const pair of raw.trim().split(",")) {
    const [phone, name] = pair.split(":");
    if (phone && name) {
      result[phone.trim()] = name.trim();
    }
  }
  return result;
}

const RESOLVED_SENDERS = parseSenders(process.env.WHATSAPP_ALLOWED_SENDERS ?? "");

function phoneFromJid(jid: string): string {
  return jid.split("@")[0];
}

// Bot's own JIDs (phone and LID) — used to detect @mentions
const BOT_JIDS = (process.env.WHATSAPP_BOT_JIDS ?? "5491139225010,279427015528605")
  .split(",")
  .map(s => s.trim())
  .filter(Boolean);

function isBotMentioned(message: MessageData["message"]): boolean {
  const mentionedJids = message?.extendedTextMessage?.contextInfo?.mentionedJid ?? [];
  return mentionedJids.some(jid => {
    const id = jid.split(/[@:]/)[0];
    return BOT_JIDS.includes(id);
  });
}

function textFromMention(text: string): string {
  // "@5491139225010 ayuda" → "BOT ayuda"
  return "BOT " + text.replace(/^@\d+\s*/i, "").trim();
}

// ── Main processor ───────────────────────────────────────────────────────────

async function processWebhook(payload: WebhookPayload) {
  if (payload.event !== "messages.upsert") return;

  const data = payload.data;
  if (!data?.key) return;

  // Only process messages from the configured group
  if (GROUP_JID && data.key.remoteJid !== GROUP_JID) return;

  // Ignore own messages
  if (data.key.fromMe) return;

  const groupJid = data.key.remoteJid;
  const senderPhone = data.key.participant ?? data.key.remoteJid;
  const senderKey = phoneFromJid(senderPhone);

  // Only respond to authorised senders
  if (!(senderKey in RESOLVED_SENDERS)) return;

  const senderName = RESOLVED_SENDERS[senderKey];
  const message = data.message;
  if (!message) return;

  // Detect message type from message keys (Baileys may send senderKeyDistributionMessage as first key)
  const messageType = data.messageType ?? "";
  const hasConversation = "conversation" in message || "extendedTextMessage" in message;
  const hasImage = "imageMessage" in message;
  const hasDocument = "documentMessage" in message;
  const hasButtonResponse = "buttonsResponseMessage" in message;
  const hasListResponse = "listResponseMessage" in message;

  // Text message
  if (hasConversation || messageType === "conversation" || messageType === "extendedTextMessage") {
    let text =
      message.conversation ?? message.extendedTextMessage?.text ?? "";

    // If bot is @mentioned (tag), convert to BOT prefix so handlers recognise it
    if (!isBotCommand(text) && isBotMentioned(message)) {
      text = textFromMention(text);
    }

    if (isBotCommand(text)) {
      // If the user has an active session, try the interactive handler first
      // before falling through to Mistral. This handles confirmations, numbers, etc.
      const { state } = await getSession(senderPhone);
      if (state !== "idle") {
        const query = text.replace(/^BOT\s+/i, "").replace(/^@\S+\s*/i, "").trim();
        const interactiveResult = await handleInteractiveTextReply(groupJid, senderPhone, senderName, query, true);
        if (interactiveResult === "handled") return;
        // "unrecognized" → silent, fall through to Mistral
      }
      await handleTextMessage(groupJid, senderPhone, senderName, text);
      return;
    }

    const interactiveResult = await handleInteractiveTextReply(groupJid, senderPhone, senderName, text);
    if (interactiveResult === "handled") {
      return;
    }

    if (interactiveResult === "unrecognized") {
      return;
    }

    return;
  }

  // Image message
  if (hasImage || messageType === "imageMessage") {
    const mimeType = message.imageMessage?.mimetype ?? "image/jpeg";
    await handleImageMessage(groupJid, senderPhone, senderName, data, mimeType);
    return;
  }

  // Document (PDF, etc.)
  if (hasDocument || messageType === "documentMessage") {
    const mimeType = message.documentMessage?.mimetype ?? "application/pdf";
    if (mimeType.startsWith("image/") || mimeType === "application/pdf") {
      await handleImageMessage(groupJid, senderPhone, senderName, data, mimeType);
    }
    return;
  }

  // Button reply
  if (hasButtonResponse || messageType === "buttonsResponseMessage") {
    const buttonId = message.buttonsResponseMessage?.selectedButtonId ?? "";
    if (buttonId) {
      await handleButtonReply(groupJid, senderPhone, senderName, buttonId);
    }
    return;
  }

  // List reply (fallback for environments where buttons aren't available)
  if (hasListResponse || messageType === "listResponseMessage") {
    const rowId = message.listResponseMessage?.singleSelectReply?.selectedRowId ?? "";
    if (rowId) {
      await handleButtonReply(groupJid, senderPhone, senderName, rowId);
    }
    return;
  }
}
