import { Hono } from 'hono';
import { db, dbGet, dbAll, users, events, tickets, payments, contacts, emailSubscribers } from '../db/index.js';
import { eq, and, ne, gte, sql, desc, inArray } from 'drizzle-orm';
import { requireAuth } from '../lib/auth.js';
import { getNow } from '../lib/utils.js';
import { eventSeatBreakdownQuery } from '../lib/capacity.js';

const adminRouter = new Hono();

// Escape a value for inclusion in a CSV cell (RFC 4180 quoting).
const csvEscape = (value: string) => {
  if (value == null) return '';
  const str = String(value);
  if (str.includes(',') || str.includes('"') || str.includes('\n') || str.includes('\r')) {
    return '"' + str.replace(/"/g, '""') + '"';
  }
  return str;
};

// Dashboard overview stats (admin)
adminRouter.get('/dashboard', requireAuth(['admin', 'organizer']), async (c) => {
  const now = getNow();
  
  // Get upcoming events with seat counts (paid + claimed, per lib/capacity.ts)
  // so the dashboard's capacity alerts reflect real availability.
  const upcomingEventsRaw = await dbAll<any>(
    (db as any)
      .select()
      .from(events)
      .where(
        and(
          eq((events as any).status, 'published'),
          gte((events as any).startDatetime, now)
        )
      )
      .orderBy((events as any).startDatetime)
      .limit(5)
  );

  const seatRows = await dbAll<any>(eventSeatBreakdownQuery(db));
  const seatsByEvent = new Map<string, { paid: number; claimed: number }>();
  for (const row of seatRows) {
    seatsByEvent.set(row.eventId, {
      paid: Number(row.paidCount) || 0,
      claimed: Number(row.claimedCount) || 0,
    });
  }
  const upcomingEvents = upcomingEventsRaw.map((event: any) => {
    const counts = seatsByEvent.get(event.id) || { paid: 0, claimed: 0 };
    return {
      ...event,
      bookedCount: counts.paid,
      claimedCount: counts.claimed,
      availableSeats: Math.max(0, (event.capacity || 0) - counts.paid - counts.claimed),
    };
  });
  
  // Get recent tickets
  const recentTickets = await dbAll(
    (db as any)
      .select()
      .from(tickets)
      .orderBy(desc((tickets as any).createdAt))
      .limit(10)
  );
  
  // Get total stats
  const totalUsers = await dbGet<any>(
    (db as any)
      .select({ count: sql<number>`count(*)` })
      .from(users)
  );
  
  const totalEvents = await dbGet<any>(
    (db as any)
      .select({ count: sql<number>`count(*)` })
      .from(events)
  );
  
  const totalTickets = await dbGet<any>(
    (db as any)
      .select({ count: sql<number>`count(*)` })
      .from(tickets)
  );
  
  const confirmedTickets = await dbGet<any>(
    (db as any)
      .select({ count: sql<number>`count(*)` })
      .from(tickets)
      .where(eq((tickets as any).status, 'confirmed'))
  );
  
  // 'pending' = checkout opened, nothing paid or claimed (informational);
  // 'pending_approval' = customer says they paid, needs admin verification (actionable).
  const pendingPayments = await dbGet<any>(
    (db as any)
      .select({ count: sql<number>`count(*)` })
      .from(payments)
      .where(eq((payments as any).status, 'pending'))
  );

  const awaitingApprovalPayments = await dbGet<any>(
    (db as any)
      .select({ count: sql<number>`count(*)` })
      .from(payments)
      .where(eq((payments as any).status, 'pending_approval'))
  );

  const onHoldPayments = await dbGet<any>(
    (db as any)
      .select({ count: sql<number>`count(*)` })
      .from(payments)
      .where(eq((payments as any).status, 'on_hold'))
  );

  const revenueRow = await 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'))
  );
  
  const totalRevenue = Number(revenueRow?.total || 0);
  
  const newContacts = await dbGet<any>(
    (db as any)
      .select({ count: sql<number>`count(*)` })
      .from(contacts)
      .where(eq((contacts as any).status, 'new'))
  );
  
  const totalSubscribers = await dbGet<any>(
    (db as any)
      .select({ count: sql<number>`count(*)` })
      .from(emailSubscribers)
      .where(eq((emailSubscribers as any).status, 'active'))
  );
  
  return c.json({
    dashboard: {
      stats: {
        totalUsers: totalUsers?.count || 0,
        totalEvents: totalEvents?.count || 0,
        totalTickets: totalTickets?.count || 0,
        confirmedTickets: confirmedTickets?.count || 0,
        pendingPayments: pendingPayments?.count || 0,
        awaitingApprovalPayments: awaitingApprovalPayments?.count || 0,
        onHoldPayments: onHoldPayments?.count || 0,
        totalRevenue,
        newContacts: newContacts?.count || 0,
        totalSubscribers: totalSubscribers?.count || 0,
      },
      upcomingEvents,
      recentTickets,
    },
  });
});

// Get analytics data (admin)
adminRouter.get('/analytics', requireAuth(['admin']), async (c) => {
  // Get events with ticket counts using grouped aggregates (avoids 3 queries per event).
  const allEvents = await dbAll<any>((db as any).select().from(events));

  const totalRows = await dbAll<any>(
    (db as any)
      .select({ eventId: (tickets as any).eventId, count: sql<number>`count(*)` })
      .from(tickets)
      .groupBy((tickets as any).eventId)
  );
  const confirmedRows = await dbAll<any>(
    (db as any)
      .select({ eventId: (tickets as any).eventId, count: sql<number>`count(*)` })
      .from(tickets)
      .where(and(eq((tickets as any).status, 'confirmed'), ne((tickets as any).isGuest, 1)))
      .groupBy((tickets as any).eventId)
  );
  const checkedInRows = await dbAll<any>(
    (db as any)
      .select({ eventId: (tickets as any).eventId, count: sql<number>`count(*)` })
      .from(tickets)
      .where(and(eq((tickets as any).status, 'checked_in'), ne((tickets as any).isGuest, 1)))
      .groupBy((tickets as any).eventId)
  );

  const toMap = (rows: any[]) => {
    const m = new Map<string, number>();
    for (const r of rows) m.set(r.eventId, Number(r.count) || 0);
    return m;
  };
  const totalMap = toMap(totalRows);
  const confirmedMap = toMap(confirmedRows);
  const checkedInMap = toMap(checkedInRows);

  const eventStats = allEvents.map((event: any) => {
    const confirmedBookings = confirmedMap.get(event.id) || 0;
    return {
      id: event.id,
      title: event.title,
      date: event.startDatetime,
      capacity: event.capacity,
      totalBookings: totalMap.get(event.id) || 0,
      confirmedBookings,
      checkedIn: checkedInMap.get(event.id) || 0,
      revenue: confirmedBookings * event.price,
    };
  });
  
  return c.json({
    analytics: {
      events: eventStats,
    },
  });
});

// Export data (admin)
adminRouter.get('/export/tickets', requireAuth(['admin']), async (c) => {
  const eventId = c.req.query('eventId');
  
  let query = (db as any).select().from(tickets);
  
  if (eventId) {
    query = query.where(eq((tickets as any).eventId, eventId));
  }
  
  const ticketList = await dbAll<any>(query);

  const userIds = [...new Set(ticketList.map((t: any) => t.userId).filter(Boolean))];
  const eventIds = [...new Set(ticketList.map((t: any) => t.eventId).filter(Boolean))];
  const ticketIds = ticketList.map((t: any) => t.id);

  const [userRows, eventRows, paymentRows] = await Promise.all([
    userIds.length ? dbAll<any>((db as any).select().from(users).where(inArray((users as any).id, userIds))) : Promise.resolve([]),
    eventIds.length ? dbAll<any>((db as any).select().from(events).where(inArray((events as any).id, eventIds))) : Promise.resolve([]),
    ticketIds.length ? dbAll<any>((db as any).select().from(payments).where(inArray((payments as any).ticketId, ticketIds))) : Promise.resolve([]),
  ]);

  const usersById = new Map(userRows.map((u: any) => [u.id, u]));
  const eventsById = new Map(eventRows.map((e: any) => [e.id, e]));
  const paymentsByTicketId = new Map(paymentRows.map((p: any) => [p.ticketId, p]));
  
  const enrichedTickets = ticketList.map((ticket: any) => {
      const user = usersById.get(ticket.userId);
      const event = eventsById.get(ticket.eventId);
      const payment = paymentsByTicketId.get(ticket.id);
      
      return {
        ticketId: ticket.id,
        ticketStatus: ticket.status,
        qrCode: ticket.qrCode,
        checkinAt: ticket.checkinAt,
        userName: user?.name,
        userEmail: user?.email,
        userPhone: user?.phone,
        attendeeRuc: ticket.attendeeRuc || user?.rucNumber || null,
        eventTitle: event?.title,
        eventDate: event?.startDatetime,
        paymentStatus: payment?.status,
        paymentAmount: payment?.amount,
        createdAt: ticket.createdAt,
      };
    });
  
  return c.json({ tickets: enrichedTickets });
});

// Export attendees for a specific event (admin) — CSV download
adminRouter.get('/events/:eventId/attendees/export', requireAuth(['admin']), async (c) => {
  const eventId = c.req.param('eventId');
  const status = c.req.query('status') || 'all'; // confirmed | checked_in | confirmed_pending | all
  const q = c.req.query('q') || '';

  // Verify event exists
  const event = await dbGet<any>(
    (db as any).select().from(events).where(eq((events as any).id, eventId))
  );
  if (!event) {
    return c.json({ error: 'Event not found' }, 404);
  }

  // Build query for tickets belonging to this event
  let conditions: any[] = [eq((tickets as any).eventId, eventId)];

  if (status === 'confirmed') {
    conditions.push(eq((tickets as any).status, 'confirmed'));
  } else if (status === 'checked_in') {
    conditions.push(eq((tickets as any).status, 'checked_in'));
  } else if (status === 'confirmed_pending') {
    conditions.push(inArray((tickets as any).status, ['confirmed', 'pending']));
  } else {
    // "all" — include everything
  }

  let ticketList = await dbAll<any>(
    (db as any)
      .select()
      .from(tickets)
      .where(conditions.length === 1 ? conditions[0] : and(...conditions))
      .orderBy(desc((tickets as any).createdAt))
  );

  // Apply text search filter in-memory
  if (q) {
    const query = q.toLowerCase();
    ticketList = ticketList.filter((t: any) => {
      const fullName = `${t.attendeeFirstName || ''} ${t.attendeeLastName || ''}`.toLowerCase();
      return (
        fullName.includes(query) ||
        (t.attendeeEmail || '').toLowerCase().includes(query) ||
        (t.attendeePhone || '').toLowerCase().includes(query) ||
        t.id.toLowerCase().includes(query)
      );
    });
  }

  // Enrich each ticket with payment data
  const rows = await Promise.all(
    ticketList.map(async (ticket: any) => {
      const payment = await dbGet<any>(
        (db as any)
          .select()
          .from(payments)
          .where(eq((payments as any).ticketId, ticket.id))
      );

      const fullName = [ticket.attendeeFirstName, ticket.attendeeLastName].filter(Boolean).join(' ');
      const isCheckedIn = ticket.status === 'checked_in';

      return {
        'Ticket ID': ticket.id,
        'Full Name': fullName,
        'Email': ticket.attendeeEmail || '',
        'Phone': ticket.attendeePhone || '',
        'RUC': ticket.attendeeRuc || '',
        'Status': ticket.status,
        'Checked In': isCheckedIn ? 'true' : 'false',
        'Check-in Time': ticket.checkinAt || '',
        'Payment Status': payment?.status || '',
        'Booked At': ticket.createdAt || '',
        'Notes': ticket.adminNote || '',
      };
    })
  );

  const columns = [
    'Ticket ID', 'Full Name', 'Email', 'Phone', 'RUC',
    'Status', 'Checked In', 'Check-in Time', 'Payment Status',
    'Booked At', 'Notes',
  ];

  const headerLine = columns.map(csvEscape).join(',');
  const dataLines = rows.map((row: any) =>
    columns.map((col) => csvEscape(row[col])).join(',')
  );

  const csvContent = '\uFEFF' + [headerLine, ...dataLines].join('\r\n'); // BOM for UTF-8

  // Build filename: event-slug-attendees-YYYY-MM-DD.csv
  const slug = (event.title || 'event')
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/(^-|-$)/g, '');
  const dateStr = new Date().toISOString().split('T')[0];
  const filename = `${slug}-attendees-${dateStr}.csv`;

  c.header('Content-Type', 'text/csv; charset=utf-8');
  c.header('Content-Disposition', `attachment; filename="${filename}"`);
  return c.body(csvContent);
});

// Legacy alias — keep old path working
adminRouter.get('/events/:eventId/export', requireAuth(['admin']), async (c) => {
  const newUrl = new URL(c.req.url);
  newUrl.pathname = newUrl.pathname.replace('/export', '/attendees/export');
  return c.redirect(newUrl.toString(), 301);
});

// Export tickets for a specific event (admin) — CSV download (confirmed/checked_in only)
adminRouter.get('/events/:eventId/tickets/export', requireAuth(['admin']), async (c) => {
  const eventId = c.req.param('eventId');
  const status = c.req.query('status') || 'all'; // confirmed | checked_in | all
  const q = c.req.query('q') || '';

  // Verify event exists
  const event = await dbGet<any>(
    (db as any).select().from(events).where(eq((events as any).id, eventId))
  );
  if (!event) {
    return c.json({ error: 'Event not found' }, 404);
  }

  // Only confirmed/checked_in for tickets export
  let conditions: any[] = [
    eq((tickets as any).eventId, eventId),
    inArray((tickets as any).status, ['confirmed', 'checked_in']),
  ];

  if (status === 'confirmed') {
    conditions = [eq((tickets as any).eventId, eventId), eq((tickets as any).status, 'confirmed')];
  } else if (status === 'checked_in') {
    conditions = [eq((tickets as any).eventId, eventId), eq((tickets as any).status, 'checked_in')];
  }

  let ticketList = await dbAll<any>(
    (db as any)
      .select()
      .from(tickets)
      .where(and(...conditions))
      .orderBy(desc((tickets as any).createdAt))
  );

  // Apply text search filter
  if (q) {
    const query = q.toLowerCase();
    ticketList = ticketList.filter((t: any) => {
      const fullName = `${t.attendeeFirstName || ''} ${t.attendeeLastName || ''}`.toLowerCase();
      return (
        fullName.includes(query) ||
        t.id.toLowerCase().includes(query)
      );
    });
  }

  const columns = ['Ticket ID', 'Booking ID', 'Attendee Name', 'RUC', 'Status', 'Check-in Time', 'Booked At'];

  const rows = ticketList.map((ticket: any) => ({
    'Ticket ID': ticket.id,
    'Booking ID': ticket.bookingId || '',
    'Attendee Name': [ticket.attendeeFirstName, ticket.attendeeLastName].filter(Boolean).join(' '),
    'RUC': ticket.attendeeRuc || '',
    'Status': ticket.status,
    'Check-in Time': ticket.checkinAt || '',
    'Booked At': ticket.createdAt || '',
  }));

  const headerLine = columns.map(csvEscape).join(',');
  const dataLines = rows.map((row: any) =>
    columns.map((col: string) => csvEscape(row[col])).join(',')
  );

  const csvContent = '\uFEFF' + [headerLine, ...dataLines].join('\r\n');

  const slug = (event.title || 'event')
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/(^-|-$)/g, '');
  const dateStr = new Date().toISOString().split('T')[0];
  const filename = `${slug}-tickets-${dateStr}.csv`;

  c.header('Content-Type', 'text/csv; charset=utf-8');
  c.header('Content-Disposition', `attachment; filename="${filename}"`);
  return c.body(csvContent);
});

// Export financial data (admin)
adminRouter.get('/export/financial', requireAuth(['admin']), async (c) => {
  const startDate = c.req.query('startDate');
  const endDate = c.req.query('endDate');
  const eventId = c.req.query('eventId');
  
  // Get all payments
  let query = (db as any).select().from(payments);
  
  const allPayments = await dbAll<any>(query);
  
  // Enrich with event and ticket data
  const 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))
      );
      
      if (!ticket) return null;
      
      const event = await dbGet<any>(
        (db as any)
          .select()
          .from(events)
          .where(eq((events as any).id, ticket.eventId))
      );
      
      // Apply filters
      if (eventId && ticket.eventId !== eventId) return null;
      if (startDate && payment.createdAt < startDate) return null;
      if (endDate && payment.createdAt > endDate) return null;
      
      return {
        paymentId: payment.id,
        amount: payment.amount,
        currency: payment.currency,
        provider: payment.provider,
        status: payment.status,
        reference: payment.reference,
        paidAt: payment.paidAt,
        createdAt: payment.createdAt,
        ticketId: ticket.id,
        attendeeFirstName: ticket.attendeeFirstName,
        attendeeLastName: ticket.attendeeLastName,
        attendeeEmail: ticket.attendeeEmail,
        attendeeRuc: ticket.attendeeRuc || null,
        eventId: event?.id,
        eventTitle: event?.title,
        eventDate: event?.startDatetime,
      };
    })
  );
  
  const filteredPayments = enrichedPayments.filter(p => p !== null);
  
  // Calculate summary
  const summary = {
    totalPayments: filteredPayments.length,
    totalPaid: filteredPayments.filter((p: any) => p.status === 'paid').reduce((sum: number, p: any) => sum + p.amount, 0),
    totalPending: filteredPayments.filter((p: any) => p.status === 'pending').reduce((sum: number, p: any) => sum + p.amount, 0),
    totalRefunded: filteredPayments.filter((p: any) => p.status === 'refunded').reduce((sum: number, p: any) => sum + p.amount, 0),
    byProvider: {
      bancard: filteredPayments.filter((p: any) => p.provider === 'bancard' && p.status === 'paid').reduce((sum: number, p: any) => sum + p.amount, 0),
      lightning: filteredPayments.filter((p: any) => p.provider === 'lightning' && p.status === 'paid').reduce((sum: number, p: any) => sum + p.amount, 0),
      cash: filteredPayments.filter((p: any) => p.provider === 'cash' && p.status === 'paid').reduce((sum: number, p: any) => sum + p.amount, 0),
    },
    paidCount: filteredPayments.filter((p: any) => p.status === 'paid').length,
    pendingCount: filteredPayments.filter((p: any) => p.status === 'pending').length,
    refundedCount: filteredPayments.filter((p: any) => p.status === 'refunded').length,
    failedCount: filteredPayments.filter((p: any) => p.status === 'failed').length,
  };
  
  return c.json({ payments: filteredPayments, summary });
});

export default adminRouter;
