import { Hono } from 'hono';
import { zValidator } from '@hono/zod-validator';
import { z } from 'zod';
import { db, dbGet, dbAll, payments, tickets, events } from '../db/index.js';
import { eq, desc, and, or, sql, inArray } from 'drizzle-orm';
import { requireAuth } from '../lib/auth.js';
import { getNow } from '../lib/utils.js';
import emailService from '../lib/email.js';
import { reserveOnHoldBooking, HoldCapacityError } from '../lib/holdRecovery.js';

const paymentsRouter = new Hono();

const updatePaymentSchema = z.object({
  status: z.enum(['pending', 'pending_approval', 'paid', 'refunded', 'failed', 'on_hold']),
  reference: z.string().optional(),
  adminNote: z.string().optional(),
});

const approvePaymentSchema = z.object({
  adminNote: z.string().optional(),
  sendEmail: z.boolean().optional().default(true),
  // Admin override: confirm the booking even when it puts the event over
  // capacity. The UI asks for explicit confirmation before sending this.
  allowOverCapacity: z.boolean().optional().default(false),
});

const rejectPaymentSchema = z.object({
  adminNote: z.string().optional(),
  sendEmail: z.boolean().optional().default(true),
});

const reopenPaymentSchema = z.object({
  adminNote: z.string().optional(),
});

// Get all payments (admin) - with ticket and event details
paymentsRouter.get('/', requireAuth(['admin']), async (c) => {
  const status = c.req.query('status');
  const provider = c.req.query('provider');
  const pendingApproval = c.req.query('pendingApproval');
  const eventId = c.req.query('eventId');
  const eventIds = c.req.query('eventIds');
  
  // Get all payments with their associated tickets
  let allPayments = await dbAll<any>(
    (db as any)
      .select()
      .from(payments)
      .orderBy(desc((payments as any).createdAt))
  );
  
  // Filter by status
  if (status) {
    allPayments = allPayments.filter((p: any) => p.status === status);
  }
  
  // Filter for pending approval specifically
  if (pendingApproval === 'true') {
    allPayments = allPayments.filter((p: any) => p.status === 'pending_approval');
  }
  
  // Filter by provider
  if (provider) {
    allPayments = allPayments.filter((p: any) => p.provider === provider);
  }
  
  // Enrich with ticket and event data
  let enrichedPayments = await Promise.all(
    allPayments.map(async (payment: any) => {
      const ticket = await dbGet<any>(
        (db as any)
          .select()
          .from(tickets)
          .where(eq((tickets as any).id, payment.ticketId))
      );
      
      let event: any = null;
      if (ticket) {
        event = await dbGet<any>(
          (db as any)
            .select()
            .from(events)
            .where(eq((events as any).id, ticket.eventId))
        );
      }
      
      return {
        ...payment,
        ticket: ticket ? {
          id: ticket.id,
          bookingId: ticket.bookingId,
          attendeeFirstName: ticket.attendeeFirstName,
          attendeeLastName: ticket.attendeeLastName,
          attendeeEmail: ticket.attendeeEmail,
          attendeePhone: ticket.attendeePhone,
          attendeeRuc: ticket.attendeeRuc,
          status: ticket.status,
        } : null,
        event: event ? {
          id: event.id,
          title: event.title,
          startDatetime: event.startDatetime,
        } : null,
      };
    })
  );

  // Filter by event(s)
  if (eventId) {
    enrichedPayments = enrichedPayments.filter((p: any) => p.event?.id === eventId);
  } else if (eventIds) {
    const ids = eventIds.split(',').map((s: string) => s.trim()).filter(Boolean);
    if (ids.length > 0) {
      enrichedPayments = enrichedPayments.filter((p: any) => p.event && ids.includes(p.event.id));
    }
  }
  
  return c.json({ payments: enrichedPayments });
});

// Get payments pending approval (admin dashboard view)
paymentsRouter.get('/pending-approval', requireAuth(['admin', 'organizer']), async (c) => {
  const pendingPayments = await dbAll<any>(
    (db as any)
      .select()
      .from(payments)
      .where(eq((payments as any).status, 'pending_approval'))
      .orderBy(desc((payments as any).userMarkedPaidAt))
  );
  
  // Enrich with ticket and event data
  const enrichedPayments = await Promise.all(
    pendingPayments.map(async (payment: any) => {
      const ticket = await dbGet<any>(
        (db as any)
          .select()
          .from(tickets)
          .where(eq((tickets as any).id, payment.ticketId))
      );
      
      let event: any = null;
      if (ticket) {
        event = await dbGet<any>(
          (db as any)
            .select()
            .from(events)
            .where(eq((events as any).id, ticket.eventId))
        );
      }
      
      return {
        ...payment,
        ticket: ticket ? {
          id: ticket.id,
          bookingId: ticket.bookingId,
          attendeeFirstName: ticket.attendeeFirstName,
          attendeeLastName: ticket.attendeeLastName,
          attendeeEmail: ticket.attendeeEmail,
          attendeePhone: ticket.attendeePhone,
          status: ticket.status,
        } : null,
        event: event ? {
          id: event.id,
          title: event.title,
          startDatetime: event.startDatetime,
        } : null,
      };
    })
  );
  
  return c.json({ payments: enrichedPayments });
});

// Get payment statistics (admin) — registered before /:id so "stats" is not parsed as an id
paymentsRouter.get('/stats/overview', requireAuth(['admin']), async (c) => {
  const [totalRow, pendingRow, paidRow, refundedRow, failedRow, onHoldRow, revenueRow] = await Promise.all([
    dbGet<any>((db as any).select({ count: sql<number>`count(*)` }).from(payments)),
    dbGet<any>((db as any).select({ count: sql<number>`count(*)` }).from(payments).where(eq((payments as any).status, 'pending'))),
    dbGet<any>((db as any).select({ count: sql<number>`count(*)` }).from(payments).where(eq((payments as any).status, 'paid'))),
    dbGet<any>((db as any).select({ count: sql<number>`count(*)` }).from(payments).where(eq((payments as any).status, 'refunded'))),
    dbGet<any>((db as any).select({ count: sql<number>`count(*)` }).from(payments).where(eq((payments as any).status, 'failed'))),
    dbGet<any>((db as any).select({ count: sql<number>`count(*)` }).from(payments).where(eq((payments as any).status, 'on_hold'))),
    dbGet<any>((db as any).select({ total: sql<number>`COALESCE(SUM(${(payments as any).amount}), 0)` }).from(payments).where(eq((payments as any).status, 'paid'))),
  ]);

  return c.json({
    stats: {
      total: Number(totalRow?.count || 0),
      pending: Number(pendingRow?.count || 0),
      paid: Number(paidRow?.count || 0),
      refunded: Number(refundedRow?.count || 0),
      failed: Number(failedRow?.count || 0),
      onHold: Number(onHoldRow?.count || 0),
      totalRevenue: Number(revenueRow?.total || 0),
    },
  });
});

// Get payment by ID (admin)
paymentsRouter.get('/:id', requireAuth(['admin', 'organizer']), async (c) => {
  const id = c.req.param('id');
  
  const payment = await dbGet<any>(
    (db as any)
      .select()
      .from(payments)
      .where(eq((payments as any).id, id))
  );
  
  if (!payment) {
    return c.json({ error: 'Payment not found' }, 404);
  }
  
  // Get associated ticket
  const ticket = await dbGet(
    (db as any)
      .select()
      .from(tickets)
      .where(eq((tickets as any).id, payment.ticketId))
  );
  
  return c.json({ payment: { ...payment, ticket } });
});

// Update payment (admin) - for manual payment confirmation
paymentsRouter.put('/:id', requireAuth(['admin', 'organizer']), zValidator('json', updatePaymentSchema), async (c) => {
  const id = c.req.param('id');
  const data = c.req.valid('json');
  const user = (c as any).get('user');
  
  const existing = await dbGet<any>(
    (db as any)
      .select()
      .from(payments)
      .where(eq((payments as any).id, id))
  );
  
  if (!existing) {
    return c.json({ error: 'Payment not found' }, 404);
  }
  
  // Confirming a failed payment must go through /approve, which re-checks event
  // capacity before re-reserving the (previously released) seat. Block the raw path.
  if (data.status === 'paid' && existing.status === 'failed') {
    return c.json({ error: 'Use the approve action to confirm a failed payment' }, 400);
  }

  const now = getNow();

  const updateData: any = { ...data, updatedAt: now };

  // If marking as paid, record who approved it and when
  if (data.status === 'paid' && existing.status !== 'paid') {
    updateData.paidAt = now;
    updateData.paidByAdminId = user.id;
  }
  
  // If payment confirmed, handle multi-ticket booking
  if (data.status === 'paid') {
    // Get the ticket associated with this payment
    const ticket = await dbGet<any>(
      (db as any)
        .select()
        .from(tickets)
        .where(eq((tickets as any).id, existing.ticketId))
    );
    
    // Check if this is part of a multi-ticket booking
    let ticketsToConfirm: any[] = [ticket];
    
    if (ticket?.bookingId) {
      // Get all tickets in this booking
      ticketsToConfirm = await dbAll(
        (db as any)
          .select()
          .from(tickets)
          .where(eq((tickets as any).bookingId, ticket.bookingId))
      );
      console.log(`[Payment] Confirming multi-ticket booking: ${ticket.bookingId}, ${ticketsToConfirm.length} tickets`);
    }
    
    // Update all payments and tickets in the booking
    for (const t of ticketsToConfirm) {
      await (db as any)
        .update(payments)
        .set(updateData)
        .where(eq((payments as any).ticketId, (t as any).id));
      
      await (db as any)
        .update(tickets)
        .set({ status: 'confirmed', paymentStatus: 'paid' })
        .where(eq((tickets as any).id, (t as any).id));
    }
    
    // Send confirmation emails asynchronously (don't block the response)
    Promise.all([
      emailService.sendBookingConfirmation(existing.ticketId),
      emailService.sendPaymentReceipt(id),
    ]).catch(err => {
      console.error('[Email] Failed to send confirmation emails:', err);
    });
  } else {
    // For non-paid status updates, just update this payment
    await (db as any)
      .update(payments)
      .set(updateData)
      .where(eq((payments as any).id, id));
  }
  
  const updated = await dbGet(
    (db as any)
      .select()
      .from(payments)
      .where(eq((payments as any).id, id))
  );
  
  return c.json({ payment: updated });
});

// Approve payment (admin) - specifically for pending_approval payments
paymentsRouter.post('/:id/approve', requireAuth(['admin', 'organizer']), zValidator('json', approvePaymentSchema), async (c) => {
  const id = c.req.param('id');
  const { adminNote, sendEmail, allowOverCapacity } = c.req.valid('json');
  const user = (c as any).get('user');

  const payment = await dbGet<any>(
    (db as any)
      .select()
      .from(payments)
      .where(eq((payments as any).id, id))
  );

  if (!payment) {
    return c.json({ error: 'Payment not found' }, 404);
  }

  // Can approve pending, pending_approval, on_hold, or failed payments.
  // 'failed' covers an admin confirming a payment that was auto-failed or rejected
  // in error; its tickets are cancelled, so recovery re-checks capacity below.
  // Bare 'pending' covers customers who paid but never clicked "I've paid".
  if (!['pending', 'pending_approval', 'on_hold', 'failed'].includes(payment.status)) {
    return c.json({ error: 'Payment cannot be approved in its current state' }, 400);
  }

  // Get the ticket associated with this payment
  const ticket = await dbGet<any>(
    (db as any)
      .select()
      .from(tickets)
      .where(eq((tickets as any).id, payment.ticketId))
  );

  // Check if this is part of a multi-ticket booking
  let ticketsToConfirm: any[] = [ticket];

  if (ticket?.bookingId) {
    // Get all tickets in this booking
    ticketsToConfirm = await dbAll(
      (db as any)
        .select()
        .from(tickets)
        .where(eq((tickets as any).bookingId, ticket.bookingId))
    );
    console.log(`[Payment] Approving multi-ticket booking: ${ticket.bookingId}, ${ticketsToConfirm.length} tickets`);
  }

  // For a failed payment, only recover tickets whose own payment is also failed.
  // This protects mixed bookings (e.g. a sibling ticket was refunded) from being
  // resurrected or having its payment flipped to paid.
  if (payment.status === 'failed') {
    const bookingPayments = await dbAll<any>(
      (db as any)
        .select({ ticketId: (payments as any).ticketId, status: (payments as any).status })
        .from(payments)
        .where(inArray((payments as any).ticketId, ticketsToConfirm.map((t: any) => t.id)))
    );
    const failedTicketIds = new Set(
      bookingPayments.filter((p: any) => p.status === 'failed').map((p: any) => p.ticketId)
    );
    ticketsToConfirm = ticketsToConfirm.filter((t: any) => failedTicketIds.has(t.id));
    if (ticketsToConfirm.length === 0) {
      return c.json({ error: 'Payment cannot be approved in its current state' }, 400);
    }
  }

  // Confirm the booking through the shared capacity-checked reservation.
  // Tickets that already hold a seat ('pending_approval' claims) cost no new
  // capacity; unseated ones (bare 'pending', on_hold, failed/cancelled) do.
  // When the event is full, the admin gets a structured over-capacity error and
  // may retry with allowOverCapacity to knowingly overbook.
  try {
    await reserveOnHoldBooking(
      ticket.eventId,
      ticketsToConfirm.map((t: any) => t.id),
      'confirmed',
      'paid',
      {
        paidByAdminId: user.id,
        fromTicketStatuses:
          payment.status === 'failed' ? ['cancelled', 'on_hold', 'pending'] : ['on_hold', 'pending'],
        skipCapacityCheck: allowOverCapacity,
        ...(adminNote ? { extraPaymentFields: { adminNote } } : {}),
      }
    );
  } catch (err) {
    if (err instanceof HoldCapacityError) {
      return c.json({
        error: 'Approving this payment puts the event over capacity.',
        code: 'EVENT_OVER_CAPACITY',
        availableSeats: err.available,
        requestedSeats: ticketsToConfirm.length,
      }, 409);
    }
    throw err;
  }

  // Send confirmation emails asynchronously (if sendEmail is true, which is the default)
  if (sendEmail !== false) {
    Promise.all([
      emailService.sendBookingConfirmation(payment.ticketId),
      emailService.sendPaymentReceipt(id),
    ]).catch(err => {
      console.error('[Email] Failed to send confirmation emails:', err);
    });
  } else {
    console.log('[Payment] Skipping confirmation emails per admin request');
  }
  
  const updated = await dbGet(
    (db as any)
      .select()
      .from(payments)
      .where(eq((payments as any).id, id))
  );
  
  return c.json({ payment: updated, message: 'Payment approved successfully' });
});

// Reject payment (admin)
paymentsRouter.post('/:id/reject', requireAuth(['admin', 'organizer']), zValidator('json', rejectPaymentSchema), async (c) => {
  const id = c.req.param('id');
  const { adminNote, sendEmail } = c.req.valid('json');
  const user = (c as any).get('user');
  
  const payment = await dbGet<any>(
    (db as any)
      .select()
      .from(payments)
      .where(eq((payments as any).id, id))
  );
  
  if (!payment) {
    return c.json({ error: 'Payment not found' }, 404);
  }
  
  if (!['pending', 'pending_approval', 'on_hold'].includes(payment.status)) {
    return c.json({ error: 'Payment cannot be rejected in its current state' }, 400);
  }
  
  const now = getNow();

  // Determine all tickets in this booking (multi-ticket bookings must be rejected together)
  const rejectTicket = await dbGet<any>(
    (db as any).select().from(tickets).where(eq((tickets as any).id, payment.ticketId))
  );
  let ticketsToReject: any[] = rejectTicket ? [rejectTicket] : [];
  if (rejectTicket?.bookingId) {
    ticketsToReject = await dbAll<any>(
      (db as any).select().from(tickets).where(eq((tickets as any).bookingId, rejectTicket.bookingId))
    );
    console.log(`[Payment] Rejecting multi-ticket booking: ${rejectTicket.bookingId}, ${ticketsToReject.length} tickets`);
  }

  for (const t of ticketsToReject) {
    // Fail the payment for each ticket in the booking
    await (db as any)
      .update(payments)
      .set({ 
        status: 'failed',
        paidByAdminId: user.id,
        adminNote: adminNote || payment.adminNote,
        updatedAt: now,
      })
      .where(eq((payments as any).ticketId, (t as any).id));

    // Cancel the ticket - booking is no longer valid after rejection
    await (db as any)
      .update(tickets)
      .set({ 
        status: 'cancelled',
        updatedAt: now,
      })
      .where(eq((tickets as any).id, (t as any).id));
  }
  
  // Send rejection email asynchronously (for manual payment methods only, if sendEmail is true)
  if (sendEmail !== false && ['bank_transfer', 'tpago'].includes(payment.provider)) {
    emailService.sendPaymentRejectionEmail(id).catch(err => {
      console.error('[Email] Failed to send payment rejection email:', err);
    });
  } else if (sendEmail === false) {
    console.log('[Payment] Skipping rejection email per admin request');
  }
  
  const updated = await dbGet(
    (db as any)
      .select()
      .from(payments)
      .where(eq((payments as any).id, id))
  );
  
  return c.json({ payment: updated, message: 'Payment rejected and booking cancelled' });
});

// Reactivate an on-hold payment back to pending_approval (admin) - re-reserves the seat
paymentsRouter.post('/:id/reactivate', requireAuth(['admin', 'organizer']), async (c) => {
  const id = c.req.param('id');

  const payment = await dbGet<any>(
    (db as any).select().from(payments).where(eq((payments as any).id, id))
  );

  if (!payment) {
    return c.json({ error: 'Payment not found' }, 404);
  }

  if (payment.status !== 'on_hold') {
    return c.json({ error: 'Only on-hold payments can be reactivated' }, 400);
  }

  const ticket = await dbGet<any>(
    (db as any).select().from(tickets).where(eq((tickets as any).id, payment.ticketId))
  );
  if (!ticket) {
    return c.json({ error: 'Ticket not found' }, 404);
  }

  let ticketsToReactivate: any[] = [ticket];
  if (ticket.bookingId) {
    ticketsToReactivate = await dbAll<any>(
      (db as any).select().from(tickets).where(eq((tickets as any).bookingId, ticket.bookingId))
    );
  }

  try {
    await reserveOnHoldBooking(
      ticket.eventId,
      ticketsToReactivate.map((t: any) => t.id),
      'pending',
      'pending_approval'
    );
  } catch (err) {
    if (err instanceof HoldCapacityError) {
      return c.json({
        error: 'This event is now full. Your spot was released after the payment deadline passed.',
      }, 400);
    }
    throw err;
  }

  const updated = await dbGet(
    (db as any).select().from(payments).where(eq((payments as any).id, id))
  );

  return c.json({ payment: updated, message: 'Booking reactivated and pending admin review' });
});

// Reopen a failed payment back to pending (admin) - re-reserves the seat.
// For when a payment was failed in error (auto-fail or rejection) and should
// return to the normal pending flow (reminders, "I've paid", approve/reject).
paymentsRouter.post('/:id/reopen', requireAuth(['admin', 'organizer']), zValidator('json', reopenPaymentSchema), async (c) => {
  const id = c.req.param('id');
  const { adminNote } = c.req.valid('json');

  const payment = await dbGet<any>(
    (db as any).select().from(payments).where(eq((payments as any).id, id))
  );

  if (!payment) {
    return c.json({ error: 'Payment not found' }, 404);
  }

  if (payment.status !== 'failed') {
    return c.json({ error: 'Only failed payments can be reopened' }, 400);
  }

  const ticket = await dbGet<any>(
    (db as any).select().from(tickets).where(eq((tickets as any).id, payment.ticketId))
  );
  if (!ticket) {
    return c.json({ error: 'Ticket not found' }, 404);
  }

  let ticketsToReopen: any[] = [ticket];
  if (ticket.bookingId) {
    ticketsToReopen = await dbAll<any>(
      (db as any).select().from(tickets).where(eq((tickets as any).bookingId, ticket.bookingId))
    );
  }

  // Only reopen tickets whose own payment is also failed (protects mixed bookings).
  const bookingPayments = await dbAll<any>(
    (db as any)
      .select({ ticketId: (payments as any).ticketId, status: (payments as any).status })
      .from(payments)
      .where(inArray((payments as any).ticketId, ticketsToReopen.map((t: any) => t.id)))
  );
  const failedTicketIds = new Set(
    bookingPayments.filter((p: any) => p.status === 'failed').map((p: any) => p.ticketId)
  );
  ticketsToReopen = ticketsToReopen.filter((t: any) => failedTicketIds.has(t.id));
  if (ticketsToReopen.length === 0) {
    return c.json({ error: 'Only failed payments can be reopened' }, 400);
  }

  const reopenIds = ticketsToReopen.map((t: any) => t.id);

  try {
    await reserveOnHoldBooking(
      ticket.eventId,
      reopenIds,
      'pending',
      'pending',
      { fromTicketStatuses: ['cancelled', 'on_hold'] }
    );
  } catch (err) {
    if (err instanceof HoldCapacityError) {
      return c.json({
        error: 'This event is now full. Your spot was released after the payment deadline passed.',
      }, 400);
    }
    throw err;
  }

  if (adminNote) {
    await (db as any)
      .update(payments)
      .set({ adminNote })
      .where(inArray((payments as any).ticketId, reopenIds));
  }

  const updated = await dbGet(
    (db as any).select().from(payments).where(eq((payments as any).id, id))
  );

  return c.json({ payment: updated, message: 'Payment reopened and set to pending' });
});

// Send payment reminder email
paymentsRouter.post('/:id/send-reminder', requireAuth(['admin', 'organizer']), async (c) => {
  const id = c.req.param('id');
  
  const payment = await dbGet<any>(
    (db as any)
      .select()
      .from(payments)
      .where(eq((payments as any).id, id))
  );
  
  if (!payment) {
    return c.json({ error: 'Payment not found' }, 404);
  }
  
  // Only allow sending reminders for pending payments
  if (!['pending', 'pending_approval'].includes(payment.status)) {
    return c.json({ error: 'Payment reminder can only be sent for pending payments' }, 400);
  }
  
  try {
    const result = await emailService.sendPaymentReminder(id);
    
    if (result.success) {
      const now = getNow();
      
      // Record when reminder was sent
      await (db as any)
        .update(payments)
        .set({ 
          reminderSentAt: now,
          updatedAt: now,
        })
        .where(eq((payments as any).id, id));
      
      return c.json({ message: 'Payment reminder sent successfully', reminderSentAt: now });
    } else {
      return c.json({ error: result.error || 'Failed to send payment reminder' }, 500);
    }
  } catch (err: any) {
    console.error('[Payment] Failed to send payment reminder:', err);
    return c.json({ error: 'Failed to send payment reminder' }, 500);
  }
});

// Update admin note
paymentsRouter.post('/:id/note', requireAuth(['admin', 'organizer']), async (c) => {
  const id = c.req.param('id');
  const body = await c.req.json();
  const { adminNote } = body;
  
  const payment = await dbGet<any>(
    (db as any)
      .select()
      .from(payments)
      .where(eq((payments as any).id, id))
  );
  
  if (!payment) {
    return c.json({ error: 'Payment not found' }, 404);
  }
  
  const now = getNow();
  
  await (db as any)
    .update(payments)
    .set({ 
      adminNote: adminNote || null,
      updatedAt: now,
    })
    .where(eq((payments as any).id, id));
  
  const updated = await dbGet(
    (db as any)
      .select()
      .from(payments)
      .where(eq((payments as any).id, id))
  );
  
  return c.json({ payment: updated, message: 'Note updated' });
});

// Process refund (admin)
paymentsRouter.post('/:id/refund', requireAuth(['admin']), async (c) => {
  const id = c.req.param('id');
  
  const payment = await dbGet<any>(
    (db as any)
      .select()
      .from(payments)
      .where(eq((payments as any).id, id))
  );
  
  if (!payment) {
    return c.json({ error: 'Payment not found' }, 404);
  }
  
  if (payment.status !== 'paid') {
    return c.json({ error: 'Can only refund paid payments' }, 400);
  }
  
  const now = getNow();

  // Refund all tickets/payments in the booking (multi-ticket bookings refund together)
  const refundTicket = await dbGet<any>(
    (db as any).select().from(tickets).where(eq((tickets as any).id, payment.ticketId))
  );
  let ticketsToRefund: any[] = refundTicket ? [refundTicket] : [];
  if (refundTicket?.bookingId) {
    ticketsToRefund = await dbAll<any>(
      (db as any).select().from(tickets).where(eq((tickets as any).bookingId, refundTicket.bookingId))
    );
    console.log(`[Payment] Refunding multi-ticket booking: ${refundTicket.bookingId}, ${ticketsToRefund.length} tickets`);
  }

  for (const t of ticketsToRefund) {
    // Only refund payments that were actually paid; leave others untouched
    await (db as any)
      .update(payments)
      .set({ status: 'refunded', updatedAt: now })
      .where(and(eq((payments as any).ticketId, (t as any).id), eq((payments as any).status, 'paid')));

    await (db as any)
      .update(tickets)
      .set({ status: 'cancelled' })
      .where(eq((tickets as any).id, (t as any).id));
  }
  
  return c.json({ message: 'Refund processed successfully' });
});

// Payment webhook (for Stripe/MercadoPago)
// Not implemented: there is deliberately NO status mutation here. Until provider
// signature verification is implemented, accepting webhooks would let anyone forge
// a "paid" status. Returns 501 and never updates payments/tickets.
paymentsRouter.post('/webhook', async (c) => {
  console.warn('Payment webhook received but provider webhooks are not implemented (no signature verification).');
  return c.json({ error: 'Webhook handling is not implemented' }, 501);
});

export default paymentsRouter;
