import { NextRequest, NextResponse } from "next/server"
import prisma from "@/lib/prisma"
import { createPledgeSchema } from "@/lib/validators"
import { generateReference } from "@/lib/reference"
import { calculateReminderSchedule } from "@/lib/reminders"
import { sendPledgeReceipt } from "@/lib/whatsapp"

export async function GET(request: NextRequest) {
  try {
    if (!prisma) return NextResponse.json({ pledges: [] })

    const sp = request.nextUrl.searchParams
    const eventId = sp.get("eventId")
    const status = sp.get("status")
    const limit = parseInt(sp.get("limit") || "50")
    const offset = parseInt(sp.get("offset") || "0")
    const sort = sp.get("sort") || "createdAt"
    const dir = sp.get("dir") === "asc" ? "asc" as const : "desc" as const
    const dueSoon = sp.get("dueSoon") === "true" // pledges due in next 7 days
    const overdue = sp.get("overdue") === "true"
    const search = sp.get("search")

    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const where: any = {}
    if (eventId) where.eventId = eventId
    if (status && status !== "all") where.status = status
    if (overdue) where.status = "overdue"
    if (dueSoon) {
      const now = new Date()
      const weekFromNow = new Date(now.getTime() + 7 * 86400000)
      where.dueDate = { gte: now, lte: weekFromNow }
      where.status = { in: ["new", "initiated"] }
    }
    if (search) {
      where.OR = [
        { donorName: { contains: search, mode: "insensitive" } },
        { donorEmail: { contains: search, mode: "insensitive" } },
        { reference: { contains: search, mode: "insensitive" } },
        { donorPhone: { contains: search } },
      ]
    }

    const orderBy = sort === "dueDate" ? { dueDate: dir } :
                     sort === "amountPence" ? { amountPence: dir } :
                     { createdAt: dir }

    const [pledges, total] = await Promise.all([
      prisma.pledge.findMany({
        where,
        include: {
          event: { select: { name: true } },
          qrSource: { select: { label: true, volunteerName: true } },
        },
        orderBy,
        take: limit,
        skip: offset,
      }),
      prisma.pledge.count({ where }),
    ])

    return NextResponse.json({
      pledges: pledges.map(p => ({
        id: p.id,
        reference: p.reference,
        amountPence: p.amountPence,
        status: p.status,
        rail: p.rail,
        donorName: p.donorName,
        donorEmail: p.donorEmail,
        donorPhone: p.donorPhone,
        giftAid: p.giftAid,
        dueDate: p.dueDate,
        planId: p.planId,
        installmentNumber: p.installmentNumber,
        installmentTotal: p.installmentTotal,
        eventName: p.event.name,
        qrSourceLabel: p.qrSource?.label || null,
        volunteerName: p.qrSource?.volunteerName || null,
        createdAt: p.createdAt,
        paidAt: p.paidAt,
      })),
      total,
      limit,
      offset,
    })
  } catch (error) {
    console.error("Pledges GET error:", error)
    return NextResponse.json({ pledges: [], total: 0, error: "Failed to load pledges" })
  }
}

export async function POST(request: NextRequest) {
  try {
    const body = await request.json()

    if (!prisma) {
      return NextResponse.json({ error: "Database not configured" }, { status: 503 })
    }

    const parsed = createPledgeSchema.safeParse(body)
    if (!parsed.success) {
      return NextResponse.json(
        { error: "Invalid data", details: parsed.error.flatten() },
        { status: 400 }
      )
    }

    const { amountPence, rail, donorName, donorEmail, donorPhone, giftAid, eventId, qrSourceId, scheduleMode, dueDate, installmentCount, installmentDates } = parsed.data

    // Get event + org
    const event = await prisma.event.findUnique({
      where: { id: eventId },
      include: { organization: true },
    })

    if (!event) {
      return NextResponse.json({ error: "Event not found" }, { status: 404 })
    }

    const org = event.organization

    // --- INSTALLMENT MODE: create N linked pledges ---
    // Auto-generate dates if not provided (1st of each month starting next month)
    let resolvedDates = installmentDates
    if (scheduleMode === "installments" && installmentCount && installmentCount > 1 && !resolvedDates?.length) {
      resolvedDates = []
      const now = new Date()
      for (let i = 0; i < installmentCount; i++) {
        const d = new Date(now.getFullYear(), now.getMonth() + 1 + i, 1)
        resolvedDates.push(d.toISOString().split("T")[0])
      }
    }
    if (scheduleMode === "installments" && installmentCount && installmentCount > 1 && resolvedDates?.length) {
      const perInstallment = Math.ceil(amountPence / installmentCount)
      const planId = `plan_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
      let firstRef = ""

      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      await prisma.$transaction(async (tx: any) => {
        for (let i = 0; i < installmentCount; i++) {
          let ref = ""
          let attempts = 0
          while (attempts < 10) {
            ref = generateReference(org.refPrefix || "PNPL", perInstallment)
            const exists = await tx.pledge.findUnique({ where: { reference: ref } })
            if (!exists) break
            attempts++
          }
          if (i === 0) firstRef = ref

          const installmentDue = new Date(resolvedDates[i])

          const p = await tx.pledge.create({
            data: {
              reference: ref,
              amountPence: perInstallment,
              currency: "GBP",
              rail,
              status: "new",
              donorName: donorName || null,
              donorEmail: donorEmail || null,
              donorPhone: donorPhone || null,
              giftAid,
              eventId,
              qrSourceId: qrSourceId || null,
              organizationId: org.id,
              dueDate: installmentDue,
              planId,
              installmentNumber: i + 1,
              installmentTotal: installmentCount,
            },
          })

          // Reminders scheduled relative to due date (2 days before, on day, 2 days after, 7 days after)
          const dueDateMs = installmentDue.getTime()
          await tx.reminder.createMany({
            data: [
              { pledgeId: p.id, step: 0, channel: "whatsapp", scheduledAt: new Date(dueDateMs - 2 * 86400000), status: "pending", payload: { templateKey: "upcoming_installment" } },
              { pledgeId: p.id, step: 1, channel: "whatsapp", scheduledAt: installmentDue, status: "pending", payload: { templateKey: "installment_due" } },
              { pledgeId: p.id, step: 2, channel: "email", scheduledAt: new Date(dueDateMs + 2 * 86400000), status: "pending", payload: { templateKey: "gentle_nudge" } },
              { pledgeId: p.id, step: 3, channel: "email", scheduledAt: new Date(dueDateMs + 7 * 86400000), status: "pending", payload: { templateKey: "urgency_impact" } },
            ],
          })

          await tx.analyticsEvent.create({
            data: { eventType: "pledge_completed", pledgeId: p.id, eventId, qrSourceId: qrSourceId || null, metadata: { amountPence: perInstallment, rail, installment: i + 1, of: installmentCount, planId } },
          })
        }
      })

      // WhatsApp receipt for the plan
      if (donorPhone) {
        const name = donorName?.split(" ")[0] || "there"
        const { sendWhatsAppMessage } = await import("@/lib/whatsapp")
        sendWhatsAppMessage(donorPhone,
          `🤲 *Pledge Confirmed!*\n\nThank you, ${name}!\n\n💷 *£${(amountPence / 100).toFixed(0)}* pledged to *${event.name}*\n📆 *${installmentCount} monthly payments* of *£${(perInstallment / 100).toFixed(0)}*\n\nFirst payment: ${new Date(resolvedDates[0]).toLocaleDateString("en-GB", { day: "numeric", month: "long" })}\n\nWe'll send you payment details before each due date.\n\nReply *STATUS* anytime to see your pledges.`
        ).catch(err => console.error("[WAHA] Installment receipt failed:", err))
      }

      return NextResponse.json({ id: planId, reference: firstRef }, { status: 201 })
    }

    // --- SINGLE PLEDGE (immediate or deferred) ---
    const parsedDueDate = scheduleMode === "date" && dueDate ? new Date(dueDate) : null

    // Generate unique reference (retry on collision)
    let reference = ""
    let attempts = 0
    while (attempts < 10) {
      reference = generateReference(org.refPrefix || "PNPL", amountPence)
      const exists = await prisma.pledge.findUnique({ where: { reference } })
      if (!exists) break
      attempts++
    }
    if (attempts >= 10) {
      return NextResponse.json({ error: "Could not generate unique reference" }, { status: 500 })
    }

    // Create pledge + payment instruction + reminder schedule in transaction
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const pledge = await prisma.$transaction(async (tx: any) => {
      const p = await tx.pledge.create({
        data: {
          reference,
          amountPence,
          currency: "GBP",
          rail,
          status: "new",
          donorName: donorName || null,
          donorEmail: donorEmail || null,
          donorPhone: donorPhone || null,
          giftAid,
          eventId,
          qrSourceId: qrSourceId || null,
          organizationId: org.id,
          dueDate: parsedDueDate,
        },
      })

      // Create payment instruction for bank transfers
      if (rail === "bank" && org.bankSortCode && org.bankAccountNo) {
        await tx.paymentInstruction.create({
          data: {
            pledgeId: p.id,
            bankReference: reference,
            bankDetails: {
              bankName: org.bankName || "",
              sortCode: org.bankSortCode,
              accountNo: org.bankAccountNo,
              accountName: org.bankAccountName || org.name,
            },
          },
        })
      }

      // Create reminder schedule — based on due date for deferred, or now for immediate
      if (parsedDueDate) {
        // DEFERRED: reminders relative to due date
        const dueDateMs = parsedDueDate.getTime()
        await tx.reminder.createMany({
          data: [
            { pledgeId: p.id, step: 0, channel: donorPhone ? "whatsapp" : "email", scheduledAt: new Date(dueDateMs - 2 * 86400000), status: "pending", payload: { templateKey: "upcoming_payment", subject: "Payment reminder — 2 days to go" } },
            { pledgeId: p.id, step: 1, channel: donorPhone ? "whatsapp" : "email", scheduledAt: parsedDueDate, status: "pending", payload: { templateKey: "payment_due_today", subject: "Your payment is due today" } },
            { pledgeId: p.id, step: 2, channel: "email", scheduledAt: new Date(dueDateMs + 3 * 86400000), status: "pending", payload: { templateKey: "gentle_nudge", subject: "Quick reminder about your pledge" } },
            { pledgeId: p.id, step: 3, channel: "email", scheduledAt: new Date(dueDateMs + 10 * 86400000), status: "pending", payload: { templateKey: "final_reminder", subject: "Final reminder about your pledge" } },
          ],
        })
      } else {
        // IMMEDIATE: reminders from now
        const schedule = calculateReminderSchedule(new Date())
        await tx.reminder.createMany({
          data: schedule.map((s) => ({
            pledgeId: p.id,
            step: s.step,
            channel: donorPhone ? "whatsapp" : s.channel, // prefer WhatsApp if phone given
            scheduledAt: s.scheduledAt,
            status: "pending",
            payload: { templateKey: s.templateKey, subject: s.subject },
          })),
        })
      }

      // Track analytics
      await tx.analyticsEvent.create({
        data: {
          eventType: "pledge_completed",
          pledgeId: p.id,
          eventId,
          qrSourceId: qrSourceId || null,
          metadata: { amountPence, rail },
        },
      })

      return p
    })

    // Build response
    const response: Record<string, unknown> = {
      id: pledge.id,
      reference: pledge.reference,
    }

    if (rail === "bank" && org.bankSortCode) {
      response.bankDetails = {
        bankName: org.bankName || "",
        sortCode: org.bankSortCode,
        accountNo: org.bankAccountNo || "",
        accountName: org.bankAccountName || org.name,
      }
    }

    // Async: Send WhatsApp receipt to donor (non-blocking)
    if (donorPhone) {
      sendPledgeReceipt(donorPhone, {
        donorName: donorName || undefined,
        amountPounds: (amountPence / 100).toFixed(0),
        eventName: event.name,
        reference: pledge.reference,
        rail,
        bankDetails: rail === "bank" && org.bankSortCode ? {
          sortCode: org.bankSortCode,
          accountNo: org.bankAccountNo || "",
          accountName: org.bankAccountName || org.name,
        } : undefined,
        orgName: org.name,
      }).catch(err => console.error("[WAHA] Receipt send failed:", err))
    }

    // Async: Notify volunteer if QR source has volunteer info
    if (qrSourceId) {
      prisma?.qrSource.findUnique({
        where: { id: qrSourceId },
        select: { volunteerName: true, label: true, pledges: { select: { amountPence: true } } },
      }).then(qr => {
        // In future: if volunteer has a phone number stored, send WhatsApp notification
        // For now, this is a no-op unless volunteer phone is added to schema
        if (qr) {
          console.log(`[PLEDGE] ${qr.volunteerName || qr.label}: +1 pledge (£${(amountPence / 100).toFixed(0)})`)
        }
      }).catch(() => {})
    }

    return NextResponse.json(response, { status: 201 })
  } catch (error) {
    console.error("Pledge creation error:", error)
    return NextResponse.json({ error: "Internal error" }, { status: 500 })
  }
}
