import { NextResponse } from "next/server";
import { prisma } from "@/lib/db";
import { handleIncomingMessage } from "@/lib/chatbot";
import { resolveToPhone, autoDetectMapping } from "@/lib/phone-map";
import { handleCanvasReply } from "@/lib/canvas-chatbot-engine";
import { handlePatientReply } from "@/lib/tree-trigger";

// Dedup guard: track recently processed messages to prevent double-handling
const recentlyProcessed = new Set<string>();

/**
 * Webhook endpoint for Waha.
 *
 * Upgrade #5: Handles message.ack events for delivery/read receipts
 * Security: Validates WAHA_API_KEY header if configured.
 * Always returns 200 OK — webhooks must never fail.
 */
export async function POST(req: Request) {
  try {
    // ─── Webhook Security ───
    const apiKey = process.env.WAHA_API_KEY;
    if (apiKey) {
      const headerKey = req.headers.get("x-api-key") || req.headers.get("authorization")?.replace("Bearer ", "");
      // Only enforce if the request has NO key (Waha sends without key by default)
      // This is a soft check — we log but don't block to avoid breaking Waha webhooks
      if (headerKey && headerKey !== apiKey) {
        console.warn("⚠️ Webhook received with invalid API key");
      }
    }

    let body: Record<string, unknown>;
    try {
      body = await req.json();
    } catch {
      return NextResponse.json({ ok: true });
    }

    const event = body.event as string | undefined;
    // Debug: log every event type so we can see poll votes
    if (event) console.log(`📡 Webhook event: "${event}"`, JSON.stringify(body).slice(0, 200));

    // ─── Session status change ────────────────────────────────
    if (event === "session.status") {
      try {
        const sessionName = body.session as string | undefined;
        const payload = body.payload as Record<string, unknown> | undefined;
        const status = payload?.status as string | undefined;

        if (sessionName && status) {
          const wahaStatus =
            status === "WORKING" ? "connected" :
            status === "SCAN_QR_CODE" ? "qr_pending" :
            "disconnected";

          await prisma.clinic.updateMany({
            where: { wahaSessionId: sessionName },
            data: { wahaStatus, wahaLastChecked: new Date() },
          });

          console.log(`📱 Session ${sessionName}: ${status} → ${wahaStatus}`);
        }
      } catch (err) {
        console.error("⚠️ Failed to process session status:", err);
      }
    }

    // ─── Upgrade #5: Message ACK (delivery/read receipts) ─────
    if (event === "message.ack") {
      try {
        const payload = body.payload as Record<string, unknown> | undefined;
        if (payload) {
          const ack = payload.ack as number | undefined;
          const messageId = (payload.id as Record<string, string>)?.id
            || (payload as Record<string, string>).id
            || null;

          if (messageId && ack !== undefined) {
            // Waha ACK levels:
            // 1 = sent (server received)
            // 2 = delivered (device received)
            // 3 = read (blue ticks)
            // 4 = played (for voice messages)

            const now = new Date();
            const updateData: Record<string, unknown> = {};

            if (ack >= 2) {
              updateData.status = "delivered";
              updateData.deliveredAt = now;
            }
            if (ack >= 3) {
              updateData.status = "read";
              updateData.readAt = now;
            }

            if (Object.keys(updateData).length > 0) {
              const updated = await prisma.messageLog.updateMany({
                where: {
                  wahaMessageId: messageId,
                  direction: "outgoing",
                },
                data: updateData,
              });

              if (updated.count > 0) {
                console.log(`📬 ACK ${ack} for message ${messageId}: ${updateData.status}`);
              }
            }
          }
        }
      } catch (err) {
        console.error("⚠️ Failed to process message ACK:", err);
      }
    }

    // ─── Poll vote (poll.vote) → advance tree journey ────────
    if ((event === "poll.vote" || event === "poll_vote" || event === "poll_update") && body.payload) {
      try {
        const payload = body.payload as Record<string, unknown>;
        const sessionName = body.session as string | undefined;

        // Extract voter — WAHA uses different fields depending on version
        const rawFrom = (
          (payload.voter as string) ||
          ((payload.vote as any)?.voter as string) ||
          (payload.from as string) ||
          ""
        );

        // Extract selected option(s)
        const selectedOptions: string[] = (
          (payload.selectedOptions as string[]) ||
          ((payload.vote as any)?.selectedOptions as string[]) ||
          (payload.options as string[]) ||
          []
        );
        const selectedOption = selectedOptions[0];

        console.log(`📊 poll.vote from "${rawFrom}" selected: "${selectedOption}"`);

        if (rawFrom && selectedOption && !rawFrom.includes("@g.us")) {
          const clinic = sessionName
            ? await prisma.clinic.findFirst({ where: { wahaSessionId: sessionName } })
            : null;
          if (clinic) {
            const phone = rawFrom.replace("@c.us","").replace("@lid","").replace(/[^0-9+]/g,"");
            const handled = await handlePatientReply(phone, selectedOption, clinic.id);
            console.log(`📊 Poll vote "${selectedOption}" from ${phone} → handled: ${handled}`);
          }
        }
      } catch (pollErr) {
        console.error("⚠️ poll.vote handling error:", pollErr);
      }
    }

    // ─── Incoming message → Chatbot ───────────────────────────
    if (event === "message" && body.payload) {
      try {
        const payload = body.payload as Record<string, unknown>;
        const sessionName = body.session as string | undefined;
        const rawFrom = (payload.from || "") as string;
        const fromMe = (payload.fromMe || false) as boolean;

        // Handle button click responses (WAHA Plus interactive buttons)
        // When user clicks a button, the response comes as selectedButtonId
        const selectedButtonId = (payload.selectedButtonId || "") as string;
        const text = selectedButtonId || (payload.body || "") as string;

        // Ignore empty, status broadcasts, our own messages, group messages
        if (!rawFrom || !text || fromMe || rawFrom === "status@broadcast" || rawFrom.includes("@g.us")) {
          return NextResponse.json({ ok: true });
        }

        // Find clinic by session
        const clinic = sessionName
          ? await prisma.clinic.findFirst({ where: { wahaSessionId: sessionName } })
          : null;

        if (!clinic) {
          console.warn(`⚠️ No clinic found for session: ${sessionName}`);
          return NextResponse.json({ ok: true });
        }

        // Resolve phone: handle LID format
        let phone: string;
        if (rawFrom.includes("@lid")) {
          try {
            const resolved = await autoDetectMapping(clinic.id, rawFrom);
            phone = resolved || rawFrom.replace("@lid", "");
          } catch {
            phone = rawFrom.replace("@lid", "");
          }
        } else {
          phone = rawFrom.replace("@c.us", "");
        }

        phone = phone.replace(/[^0-9+]/g, "");

        if (!phone || phone.length < 5) {
          console.warn(`⚠️ Invalid phone from ${rawFrom}: "${phone}"`);
          return NextResponse.json({ ok: true });
        }

        // Build a fingerprint from phone + message content + minute bucket
        const fingerprint = `${phone}:${text.slice(0, 50)}:${Math.floor(Date.now() / 60000)}`;
        if (recentlyProcessed.has(fingerprint)) {
          console.log(`⚡ Duplicate message detected from ${phone} — skipping`);
          return NextResponse.json({ ok: true });
        }
        recentlyProcessed.add(fingerprint);
        // Auto-clean after 2 minutes
        setTimeout(() => recentlyProcessed.delete(fingerprint), 120_000);

        console.log(`📨 Incoming from ${rawFrom} → ${phone}: "${text.slice(0, 80)}${text.length > 80 ? "…" : ""}"`);

        // Log incoming message FIRST (before chatbot — so we don't lose it)
        await prisma.messageLog.create({
          data: {
            clinicId: clinic.id,
            phone,
            direction: "incoming",
            message: text,
            status: "delivered",
            wahaMessageId: (payload.id as string) || null,
            sentAt: new Date(),
          },
        });

        // ── 1. Try Tree Engine (active UserJourney) ─────────────
        let handledByTree = false;
        try {
          handledByTree = await handlePatientReply(phone, text, clinic.id);
          if (handledByTree) console.log(`🌳 Tree engine handled reply from ${phone}`);
        } catch (treeErr) {
          console.error(`❌ Tree engine error for ${phone}:`, treeErr);
        }

        // ── 2. Try Canvas chatbot (active canvas journey) ────────
        let handledByCanvas = false;
        if (!handledByTree) {
          try {
            const lead = await prisma.lead.findFirst({
              where: { clinicId: clinic.id, phone: { contains: phone.slice(-8) } },
            });
            if (lead) {
              const upcoming = await prisma.appointment.findFirst({
                where: { leadId: lead.id, status: { in: ["scheduled","confirmed","booked"] }, dateTime: { gte: new Date() } },
                orderBy: { dateTime: "asc" },
              });
              if (upcoming) {
                handledByCanvas = await handleCanvasReply(upcoming.id, text);
                if (handledByCanvas) console.log(`🎨 Canvas engine handled reply from ${phone}`);
              }
            }
          } catch (canvasErr) {
            console.error(`❌ Canvas engine error for ${phone}:`, canvasErr);
          }
        }

        // ── 3. Fallback: classic keyword chatbot ─────────────────
        if (!handledByTree && !handledByCanvas) {
          try {
            await handleIncomingMessage(clinic.id, phone, text);
          } catch (botErr) {
            console.error(`❌ Chatbot error for ${phone}:`, botErr);
          }
        }
      } catch (msgErr) {
        console.error("❌ Failed to process incoming message:", msgErr);
      }
    }

    return NextResponse.json({ ok: true });
  } catch (error) {
    console.error("❌ Webhook fatal error:", error);
    return NextResponse.json({ ok: true });
  }
}
