import { NextResponse } from "next/server";
import { prisma } from "@/lib/db";
import { getSession } from "@/lib/auth";
import { scheduleReminders, sendBookingConfirmation, generateConfirmToken } from "@/lib/reminders";
import { triggerTree, sendDirectBookingConfirmation } from "@/lib/tree-trigger";

export async function GET() {
  const session = await getSession();
  if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });

  const appointments = await prisma.appointment.findMany({
    where: { clinicId: session.id },
    include: {
      lead: true,
      treatment: true,
      scheduledReminders: {
        include: { template: true },
        orderBy: { scheduledFor: "asc" },
      },
    },
    orderBy: { dateTime: "asc" },
  });

  return NextResponse.json(appointments);
}

export async function POST(req: Request) {
  const session = await getSession();
  if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });

  let body: Record<string, unknown>;
  try {
    body = await req.json();
  } catch {
    return NextResponse.json({ error: "Invalid JSON" }, { status: 400 });
  }

  if (!body.leadId || !body.treatmentId || !body.dateTime) {
    return NextResponse.json({ error: "Lead, treatment, and date/time are required" }, { status: 400 });
  }

  const dateTime = new Date(body.dateTime as string);
  if (isNaN(dateTime.getTime())) {
    return NextResponse.json({ error: "Invalid date/time format" }, { status: 400 });
  }

  // Don't allow booking in the past
  if (dateTime < new Date()) {
    return NextResponse.json({ error: "Cannot book appointments in the past" }, { status: 400 });
  }

  // Verify lead exists and belongs to this clinic
  const lead = await prisma.lead.findFirst({
    where: { id: body.leadId as string, clinicId: session.id },
  });
  if (!lead) {
    return NextResponse.json({ error: "Lead not found" }, { status: 404 });
  }

  // Verify treatment exists, belongs to this clinic, and is active
  const treatment = await prisma.treatment.findFirst({
    where: { id: body.treatmentId as string, clinicId: session.id, isActive: true },
  });
  if (!treatment) {
    return NextResponse.json({ error: "Treatment not found or inactive" }, { status: 404 });
  }

  // ═══ Upgrade #3: Double-booking prevention ═══

  // Check 1: Same lead already has an active appointment at overlapping time
  const appointmentEndTime = new Date(dateTime.getTime() + treatment.duration * 60000);
  const leadConflict = await prisma.appointment.findFirst({
    where: {
      leadId: body.leadId as string,
      status: { in: ["scheduled", "confirmed", "booked"] },
      dateTime: { gte: new Date() },
      // Overlapping: existing appointment starts before new one ends
      // AND existing appointment ends after new one starts
      AND: [
        { dateTime: { lt: appointmentEndTime } },
      ],
    },
    include: { treatment: true },
  });

  if (leadConflict) {
    // Check if it truly overlaps (consider duration of existing appointment)
    const existingEnd = new Date(new Date(leadConflict.dateTime).getTime() + leadConflict.treatment.duration * 60000);
    if (dateTime < existingEnd && appointmentEndTime > new Date(leadConflict.dateTime)) {
      const conflictDate = new Date(leadConflict.dateTime).toLocaleDateString("en-US", {
        weekday: "short", month: "short", day: "numeric", hour: "numeric", minute: "2-digit",
      });
      return NextResponse.json({
        error: `This patient already has an appointment at ${conflictDate} (${leadConflict.treatment.name}). Please cancel or reschedule the existing one first.`,
      }, { status: 409 });
    }
  }

  // Check 2: Time slot capacity (no more than 3 overlapping appointments)
  const slotConflicts = await prisma.appointment.count({
    where: {
      clinicId: session.id,
      status: { in: ["scheduled", "confirmed", "booked", "arrived", "in_progress"] },
      dateTime: {
        gte: new Date(dateTime.getTime() - 60 * 60000), // 1 hour window
        lte: new Date(dateTime.getTime() + 60 * 60000),
      },
    },
  });

  // Soft warning at 3+, hard block at 10 (configurable per clinic later)
  if (slotConflicts >= 10) {
    return NextResponse.json({
      error: "This time slot is fully booked. Please choose a different time.",
    }, { status: 409 });
  }

  // ═══ Create appointment with confirm token (Upgrade #6) ═══
  const confirmToken = generateConfirmToken();

  const appointment = await prisma.appointment.create({
    data: {
      clinicId: session.id,
      leadId: body.leadId as string,
      treatmentId: body.treatmentId as string,
      dateTime,
      confirmToken,
      notes: (body.notes as string) || null,
    },
    include: { lead: true, treatment: true },
  });

  // Update lead status (non-blocking)
  try {
    await prisma.lead.update({
      where: { id: body.leadId as string },
      data: { status: "booked" },
    });
  } catch (err) {
    console.error("⚠️ Failed to update lead status to booked:", err);
  }

  // ── 🌳 TRIGGER BOOKING TREE (primary) — fire & forget ──
  // The tree handles the full conversation (welcome → reminder → confirm → follow-up).
  // Only fall back to legacy reminders if NO active tree exists.
  triggerTree(appointment.id, "booking_created").then(result => {
    if (result.started) {
      console.log(`🌳 Tree "${result.treeName}" started → journey ${result.journeyId}`);
      // Tree is handling reminders — also schedule timed follow-ups for 3d/1d/2h before
      scheduleReminders(appointment.id).catch(err =>
        console.error("⚠️ scheduleReminders (after tree) failed:", err)
      );
    } else {
      // No active tree → direct confirmation + legacy schedule
      console.log(`📨 No tree (${result.error}) → direct confirmation + legacy schedule`);
      sendDirectBookingConfirmation(appointment.id).catch(err =>
        console.error("⚠️ Direct confirmation failed:", err)
      );
      scheduleReminders(appointment.id).catch(err =>
        console.error("⚠️ scheduleReminders failed:", err)
      );
    }
  }).catch(err => {
    console.error("❌ triggerTree failed:", err);
    sendDirectBookingConfirmation(appointment.id).catch(() => {});
    scheduleReminders(appointment.id).catch(() => {});
  });

  // Include slot warning if applicable
  const response: Record<string, unknown> = { ...appointment };
  if (slotConflicts >= 3) {
    response._warning = `Note: There are ${slotConflicts + 1} appointments in this time window.`;
  }

  return NextResponse.json(response);
}
