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

const adminRouter = new Hono();

// Dashboard overview stats (admin)
adminRouter.get('/dashboard', requireAuth(['admin', 'organizer']), async (c) => {
  const now = getNow();
  
  // Get upcoming events
  const upcomingEvents = await dbAll(
    (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)
  );
  
  // 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'))
  );
  
  const pendingPayments = await dbGet<any>(
    (db as any)
      .select({ count: sql<number>`count(*)` })
      .from(payments)
      .where(eq((payments as any).status, 'pending'))
  );
  
  const paidPayments = await dbAll<any>(
    (db as any)
      .select()
      .from(payments)
      .where(eq((payments as any).status, 'paid'))
  );
  
  const totalRevenue = paidPayments.reduce((sum: number, p: any) => sum + Number(p.amount || 0), 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,
        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
  const allEvents = await dbAll<any>((db as any).select().from(events));
  
  const eventStats = await Promise.all(
    allEvents.map(async (event: any) => {
      const ticketCount = await dbGet<any>(
        (db as any)
          .select({ count: sql<number>`count(*)` })
          .from(tickets)
          .where(eq((tickets as any).eventId, event.id))
      );
      
      const confirmedCount = await dbGet<any>(
        (db as any)
          .select({ count: sql<number>`count(*)` })
          .from(tickets)
          .where(
            and(
              eq((tickets as any).eventId, event.id),
              eq((tickets as any).status, 'confirmed')
            )
          )
      );
      
      const checkedInCount = await dbGet<any>(
        (db as any)
          .select({ count: sql<number>`count(*)` })
          .from(tickets)
          .where(
            and(
              eq((tickets as any).eventId, event.id),
              eq((tickets as any).status, 'checked_in')
            )
          )
      );
      
      return {
        id: event.id,
        title: event.title,
        date: event.startDatetime,
        capacity: event.capacity,
        totalBookings: ticketCount?.count || 0,
        confirmedBookings: confirmedCount?.count || 0,
        checkedIn: checkedInCount?.count || 0,
        revenue: (confirmedCount?.count || 0) * 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);
  
  // Get user and event details for each ticket
  const enrichedTickets = await Promise.all(
    ticketList.map(async (ticket: any) => {
      const user = await dbGet<any>(
        (db as any)
          .select()
          .from(users)
          .where(eq((users as any).id, ticket.userId))
      );
      
      const event = await dbGet<any>(
        (db as any)
          .select()
          .from(events)
          .where(eq((events as any).id, ticket.eventId))
      );
      
      const payment = await dbGet<any>(
        (db as any)
          .select()
          .from(payments)
          .where(eq((payments as any).ticketId, ticket.id))
      );
      
      return {
        ticketId: ticket.id,
        ticketStatus: ticket.status,
        qrCode: ticket.qrCode,
        checkinAt: ticket.checkinAt,
        userName: user?.name,
        userEmail: user?.email,
        userPhone: user?.phone,
        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 || '',
        'Status': ticket.status,
        'Checked In': isCheckedIn ? 'true' : 'false',
        'Check-in Time': ticket.checkinAt || '',
        'Payment Status': payment?.status || '',
        'Booked At': ticket.createdAt || '',
        'Notes': ticket.adminNote || '',
      };
    })
  );

  // Generate CSV
  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;
  };

  const columns = [
    'Ticket ID', 'Full Name', 'Email', 'Phone',
    '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 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;
  };

  const columns = ['Ticket ID', 'Booking ID', 'Attendee Name', '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(' '),
    '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,
        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;
