"use client";

import React, { useEffect, useMemo, useState } from "react";
import { useAuth } from "@/hooks/useAuth";
import { apiFetch } from "@/lib/api";
import { downloadCsv, mailtoReport, openPrintWindow } from "@/lib/export";

// Common small UI controls
function Section({ title, children, actions }: { title: string; children: React.ReactNode; actions?: React.ReactNode }) {
  return (
    <div className="border rounded-xl p-4 bg-white shadow-sm mb-6">
      <div className="flex items-center justify-between mb-3">
        <div className="text-lg font-semibold">{title}</div>
        <div className="flex gap-2">{actions}</div>
      </div>
      {children}
    </div>
  );
}

function MultiSelect({ options, value, onChange, className }: { options: { value: string; label: string }[]; value: string[]; onChange: (v: string[]) => void; className?: string }) {
  const toggle = (v: string) => {
    const set = new Set(value);
    if (set.has(v)) set.delete(v); else set.add(v);
    onChange(Array.from(set));
  };
  return (
    <div className={"flex flex-wrap gap-2 " + (className || '')}>
      {options.map(opt => (
        <label key={opt.value} className={"px-2 py-1 text-xs rounded border cursor-pointer " + (value.includes(opt.value) ? "bg-indigo-600 text-white border-indigo-600" : "bg-white text-gray-800 border-gray-200") }>
          <input type="checkbox" className="hidden" checked={value.includes(opt.value)} onChange={() => toggle(opt.value)} />
          {opt.label}
        </label>
      ))}
    </div>
  );
}

export default function Reports() {
  const { token, user } = useAuth();
  const role = user?.role || 'user';
  const canView = role === 'admin' || role === 'supervisor';

  const [events, setEvents] = useState<any[]>([]);
  const [loadingEvents, setLoadingEvents] = useState(false);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    (async () => {
      try {
        setLoadingEvents(true);
        const evs = await apiFetch<any[]>("/api/events/all?includePast=true", { authToken: token || undefined });
        setEvents(Array.isArray(evs) ? evs : []);
      } catch (e: any) {
        setError(e?.message || 'Failed to load events');
      } finally {
        setLoadingEvents(false);
      }
    })();
  }, [token, role]);

  // Filters state
  const [dateFrom, setDateFrom] = useState<string>("");
  const [dateTo, setDateTo] = useState<string>("");
  const [selectedEvents, setSelectedEvents] = useState<string[]>([]);
  const [attendeesEventId, setAttendeesEventId] = useState<string>("");
  const [includeCancelled, setIncludeCancelled] = useState<boolean>(false);
  const [includePastEvents, setIncludePastEvents] = useState<boolean>(false);

  // DATA
  const [paymentsByEvent, setPaymentsByEvent] = useState<Record<string, any[]>>({});
  const [registrationsByEvent, setRegistrationsByEvent] = useState<Record<string, any[]>>({});
  const [loading, setLoading] = useState(false);

  // Load initial selected events
  useEffect(() => {
    if (events.length > 0 && selectedEvents.length === 0) {
      const nowIso = new Date().toISOString();
      const filtered = events.filter(ev => includePastEvents || !ev.endDate || new Date(ev.endDate).toISOString() >= nowIso);
      const ids = filtered.map(ev => ev.id);
      setSelectedEvents(ids.slice(0, Math.min(ids.length, 3))); // pick first few by default
      if (!attendeesEventId && ids.length > 0) setAttendeesEventId(ids[0]);
    }
  }, [events, includePastEvents, attendeesEventId]);

  // Fetch payments per selected event (works for staff via /event/:id, and for supervisor/admin we could also use this)
  const loadPayments = async (eventIds: string[]) => {
    if (!token) return;
    setLoading(true);
    try {
      const byEv: Record<string, any[]> = {};
      for (const id of eventIds) {
        try {
          const list = await apiFetch<any[]>(`/api/payments/event/${encodeURIComponent(id)}`, { authToken: token });
          byEv[id] = Array.isArray(list) ? list : [];
        } catch (e) {
          byEv[id] = [];
        }
      }
      setPaymentsByEvent(byEv);
    } finally {
      setLoading(false);
    }
  };

  // Fetch registrations for selected/attendees events
  const loadRegistrations = async (eventIds: string[]) => {
    if (!token) return;
    setLoading(true);
    try {
      const byEv: Record<string, any[]> = {};
      for (const id of eventIds) {
        try {
          const list = await apiFetch<any[]>(`/api/registrations/event/${encodeURIComponent(id)}`, { authToken: token });
          byEv[id] = Array.isArray(list) ? list : [];
        } catch (e) {
          byEv[id] = [];
        }
      }
      setRegistrationsByEvent(byEv);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    if (selectedEvents.length > 0) {
      loadPayments(selectedEvents);
      loadRegistrations(selectedEvents);
    }
  }, [token, selectedEvents]);

  // Helpers
  const paymentsRows = useMemo(() => {
    // Flatten to rows applying date filter, grouped by event then user in presentation
    const df = dateFrom ? new Date(dateFrom).getTime() : null;
    const dt = dateTo ? new Date(dateTo).getTime() : null;
    const rows: { eventId: string; eventTitle: string; userName: string; userEmail?: string; amount: number; method: string; isDonation?: boolean; createdAt: string; registrationId?: string }[] = [];
    for (const evId of Object.keys(paymentsByEvent)) {
      const ev = events.find(e => e.id === evId);
      const evTitle = ev?.title || evId;
      for (const p of paymentsByEvent[evId] || []) {
        const t = new Date(p.createdAt).getTime();
        if ((df && t < df) || (dt && t > dt)) continue;
        // For reporting: if it's a donation, show the payer; otherwise show the user assigned to the registration
        const user = p.isDonation ? (p.user || {}) : ((p.registration?.user || p.user) || {});
        rows.push({
          eventId: evId,
          eventTitle: evTitle,
          userName: user?.name || user?.email || p.userId || 'User',
          userEmail: user?.email,
          amount: p.amount,
          method: p.method,
          isDonation: p.isDonation,
          createdAt: p.createdAt,
          registrationId: p.registrationId || undefined,
        });
      }
    }
    // Sort by event, then user, then date
    rows.sort((a,b) => (a.eventTitle.localeCompare(b.eventTitle) || (a.userName || '').localeCompare(b.userName || '') || new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()));
    return rows;
  }, [paymentsByEvent, dateFrom, dateTo, events]);

  const attendeesRows = useMemo(() => {
    const evId = attendeesEventId;
    const regs = registrationsByEvent[evId] || [];
    const filtered = regs.filter((r: any) => includeCancelled ? true : (r.status !== 'cancelled'));
    const rows = filtered.map((r: any) => ({
      name: r.user?.name || r.userId,
      email: r.user?.email,
      status: r.status,
      options: (r.registrationOptions || []).map((ro: any) => `${ro.eventOption?.name || 'Option'} x${ro.quantity}`).join('; '),
      registeredAt: r.createdAt,
    }));
    rows.sort((a: any, b: any) => (a.name || '').localeCompare(b.name || ''));
    return rows;
  }, [registrationsByEvent, attendeesEventId, includeCancelled]);

  const regTypeCounts = useMemo(() => {
    // For selectedEvents gather counts of eventOption.name quantities
    const counts: Record<string, Record<string, number>> = {}; // eventId -> optionName -> qty
    for (const evId of selectedEvents) {
      const regs = registrationsByEvent[evId] || [];
      counts[evId] = counts[evId] || {};
      for (const r of regs) {
        if (r.status === 'cancelled') continue; // default exclude
        for (const ro of (r.registrationOptions || [])) {
          const name = ro.eventOption?.name || 'Option';
          const qty = ro.quantity || 0;
          counts[evId][name] = (counts[evId][name] || 0) + qty;
        }
      }
    }
    return counts;
  }, [registrationsByEvent, selectedEvents]);

  // Actions for each report
  const exportPaymentsCsv = () => {
    downloadCsv(`payments_${new Date().toISOString().slice(0,10)}`, paymentsRows.map(r => ({
      Event: r.eventTitle,
      User: r.userName,
      Email: r.userEmail || '',
      Amount: r.amount,
      Method: r.method,
      Donation: r.isDonation ? 'Yes' : 'No',
      Date: new Date(r.createdAt).toLocaleString()
    })));
  };
  const printPayments = () => {
    const html = tableHtml(['Event','User','Email','Amount','Method','Donation','Date'], paymentsRows.map(r => [
      r.eventTitle,
      r.userName,
      r.userEmail || '',
      String(r.amount),
      r.method,
      r.isDonation ? 'Yes' : 'No',
      new Date(r.createdAt).toLocaleString()
    ]));
    openPrintWindow('Payments Report', html);
  };
  const emailPayments = () => {
    const summary = `Payments report generated on ${new Date().toLocaleString()}\nFilters: from ${dateFrom || '-'} to ${dateTo || '-'}; Events: ${selectedEvents.length}`;
    mailtoReport('Payments Report', summary + '\n\nPlease find the CSV/PDF attached.');
  };

  const exportAttendeesCsv = () => {
    downloadCsv(`attendees_${attendeesEventId}_${new Date().toISOString().slice(0,10)}`, attendeesRows.map(r => ({
      Name: r.name,
      Email: r.email || '',
      Status: r.status,
      Options: r.options,
      RegisteredAt: new Date(r.registeredAt).toLocaleString()
    })));
  };
  const printAttendees = () => {
    const html = tableHtml(['Name','Email','Status','Options','Registered At'], attendeesRows.map(r => [r.name, r.email || '', r.status, r.options, new Date(r.registeredAt).toLocaleString()]));
    openPrintWindow('Attendees Report', html);
  };
  const emailAttendees = () => {
    const ev = events.find(e => e.id === attendeesEventId);
    const summary = `Attendees for ${ev?.title || attendeesEventId} generated on ${new Date().toLocaleString()}\nInclude cancelled: ${includeCancelled ? 'Yes' : 'No'}`;
    mailtoReport('Attendees Report', summary + '\n\nPlease find the CSV/PDF attached.');
  };

  const exportRegTypesCsv = () => {
    const rows: any[] = [];
    for (const evId of Object.keys(regTypeCounts)) {
      const ev = events.find(e => e.id === evId);
      const byType = regTypeCounts[evId];
      for (const type of Object.keys(byType)) rows.push({ Event: ev?.title || evId, Type: type, Quantity: byType[type] });
    }
    downloadCsv(`registration_types_${new Date().toISOString().slice(0,10)}`, rows);
  };
  const printRegTypes = () => {
    const rows: string[][] = [];
    for (const evId of Object.keys(regTypeCounts)) {
      const ev = events.find(e => e.id === evId);
      const byType = regTypeCounts[evId];
      for (const type of Object.keys(byType)) rows.push([ev?.title || evId, type, String(byType[type])]);
    }
    const html = tableHtml(['Event','Type','Quantity'], rows);
    openPrintWindow('Registration Types Report', html);
  };
  const emailRegTypes = () => {
    const summary = `Registration types report generated on ${new Date().toLocaleString()} for ${Object.keys(regTypeCounts).length} event(s).`;
    mailtoReport('Registration Types Report', summary + '\n\nPlease find the CSV/PDF attached.');
  };

  // Extra useful report: Ticket usage summary per event (Used vs Unused, requires ticket scans info already available via tickets API on staff pages)
  const [ticketUsage, setTicketUsage] = useState<Record<string, { used: number; unused: number }>>({});
  const loadTicketUsage = async (eventIds: string[]) => {
    if (!token) return;
    const result: Record<string, { used: number; unused: number }> = {};
    for (const id of eventIds) {
      try {
        const tickets = await apiFetch<any[]>(`/api/tickets/event/${encodeURIComponent(id)}`, { authToken: token });
        const used = tickets.filter(t => t.isUsed).length;
        const unused = tickets.filter(t => !t.isUsed).length;
        result[id] = { used, unused };
      } catch (e) {
        result[id] = { used: 0, unused: 0 };
      }
    }
    setTicketUsage(result);
  };
  useEffect(() => { if (selectedEvents.length) loadTicketUsage(selectedEvents); }, [token, selectedEvents]);

  const exportUsageCsv = () => {
    const rows: any[] = [];
    for (const evId of Object.keys(ticketUsage)) {
      const ev = events.find(e => e.id === evId);
      rows.push({ Event: ev?.title || evId, Used: ticketUsage[evId].used, Unused: ticketUsage[evId].unused });
    }
    downloadCsv(`ticket_usage_${new Date().toISOString().slice(0,10)}`, rows);
  };
  const printUsage = () => {
    const rows: string[][] = [];
    for (const evId of Object.keys(ticketUsage)) {
      const ev = events.find(e => e.id === evId);
      const tu = ticketUsage[evId];
      rows.push([ev?.title || evId, String(tu.used), String(tu.unused)]);
    }
    const html = tableHtml(['Event','Used','Unused'], rows);
    openPrintWindow('Ticket Usage Report', html);
  };
  const emailUsage = () => {
    const summary = `Ticket usage report generated on ${new Date().toLocaleString()} for ${Object.keys(ticketUsage).length} event(s).`;
    mailtoReport('Ticket Usage Report', summary + '\n\nPlease find the CSV/PDF attached.');
  };

  // UI
  return (
    <div>
      {!canView && (
        <div className="p-3 border rounded bg-yellow-50 text-yellow-800 text-sm mb-4">
          You need supervisor or admin access to view reports.
        </div>
      )}

      {error && <div className="p-3 mb-3 border rounded bg-red-50 text-red-700 text-sm">{error}</div>}

      <div className="border rounded-xl p-4 bg-white shadow-sm mb-6">
        <div className="text-sm font-medium mb-2">Global filters</div>
        <div className="flex flex-wrap items-end gap-3">
          <div>
            <label className="block text-xs text-gray-600 mb-1">From</label>
            <input type="date" className="border rounded px-3 py-2 text-sm" value={dateFrom} onChange={e => setDateFrom(e.target.value)} />
          </div>
          <div>
            <label className="block text-xs text-gray-600 mb-1">To</label>
            <input type="date" className="border rounded px-3 py-2 text-sm" value={dateTo} onChange={e => setDateTo(e.target.value)} />
          </div>
          <div className="flex-1 min-w-64">
            <label className="block text-xs text-gray-600 mb-1">Select events</label>
            <MultiSelect
              options={events.map(ev => ({ value: ev.id, label: ev.title }))}
              value={selectedEvents}
              onChange={setSelectedEvents}
            />
          </div>
          <label className="flex items-center gap-2 text-sm">
            <input type="checkbox" checked={includePastEvents} onChange={e => setIncludePastEvents(e.target.checked)} /> Include past events in list
          </label>
          <button onClick={() => { loadPayments(selectedEvents); loadRegistrations(selectedEvents); }} className="px-3 py-2 text-sm rounded bg-gray-100 hover:bg-gray-200">Refresh data</button>
        </div>
      </div>

      <Section
        title="Payments between dates (grouped by event then user)"
        actions={
          <>
            <button className="px-3 py-1.5 text-sm rounded border" onClick={exportPaymentsCsv}>Export CSV</button>
            <button className="px-3 py-1.5 text-sm rounded border" onClick={printPayments}>Save as PDF</button>
            <button className="px-3 py-1.5 text-sm rounded border" onClick={emailPayments}>Email</button>
          </>
        }
      >
        {loading && <div className="text-sm text-gray-500 mb-2">Loading…</div>}
        <div className="overflow-auto">
          <table className="min-w-[640px]">
            <thead>
              <tr>
                <th>Event</th>
                <th>User</th>
                <th>Email</th>
                <th>Amount</th>
                <th>Method</th>
                <th>Donation</th>
                <th>Date</th>
              </tr>
            </thead>
            <tbody>
              {paymentsRows.length === 0 ? (
                <tr><td colSpan={7} className="text-sm text-gray-500">No payments match the selected filters.</td></tr>
              ) : paymentsRows.map((r, idx) => (
                <tr key={idx}>
                  <td>{r.eventTitle}</td>
                  <td>{r.userName}</td>
                  <td>{r.userEmail || ''}</td>
                  <td>R {Number(r.amount).toFixed(2)}</td>
                  <td>{r.method}</td>
                  <td>{r.isDonation ? 'Yes' : 'No'}</td>
                  <td>{new Date(r.createdAt).toLocaleString()}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </Section>

      <Section
        title="Attendees per event and registration status"
        actions={
          <>
            <button className="px-3 py-1.5 text-sm rounded border" onClick={exportAttendeesCsv}>Export CSV</button>
            <button className="px-3 py-1.5 text-sm rounded border" onClick={printAttendees}>Save as PDF</button>
            <button className="px-3 py-1.5 text-sm rounded border" onClick={emailAttendees}>Email</button>
          </>
        }
      >
        <div className="flex flex-wrap items-center gap-3 mb-3">
          <label className="text-sm">
            <span className="text-gray-600 mr-2">Event</span>
            <select className="border rounded px-3 py-2 text-sm" value={attendeesEventId} onChange={e => setAttendeesEventId(e.target.value)}>
              {events.map(ev => (<option key={ev.id} value={ev.id}>{ev.title}</option>))}
            </select>
          </label>
          <label className="flex items-center gap-2 text-sm">
            <input type="checkbox" checked={includeCancelled} onChange={e => setIncludeCancelled(e.target.checked)} /> Include cancelled registrations
          </label>
          <button className="px-3 py-1.5 text-sm rounded border" onClick={() => loadRegistrations([attendeesEventId])}>Refresh</button>
        </div>
        <div className="overflow-auto">
          <table className="min-w-[640px]">
            <thead>
              <tr>
                <th>Name</th>
                <th>Email</th>
                <th>Status</th>
                <th>Options</th>
                <th>Registered at</th>
              </tr>
            </thead>
            <tbody>
              {attendeesRows.length === 0 ? (
                <tr><td colSpan={5} className="text-sm text-gray-500">No attendees for selected filters.</td></tr>
              ) : attendeesRows.map((r, idx) => (
                <tr key={idx}>
                  <td>{r.name}</td>
                  <td>{r.email || ''}</td>
                  <td className="capitalize">{r.status}</td>
                  <td>{r.options}</td>
                  <td>{new Date(r.registeredAt).toLocaleString()}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </Section>

      <Section
        title="Registration type counts per event"
        actions={
          <>
            <button className="px-3 py-1.5 text-sm rounded border" onClick={exportRegTypesCsv}>Export CSV</button>
            <button className="px-3 py-1.5 text-sm rounded border" onClick={printRegTypes}>Save as PDF</button>
            <button className="px-3 py-1.5 text-sm rounded border" onClick={emailRegTypes}>Email</button>
          </>
        }
      >
        <div className="overflow-auto">
          <table className="min-w-[480px]">
            <thead>
              <tr>
                <th>Event</th>
                <th>Registration Type</th>
                <th>Quantity</th>
              </tr>
            </thead>
            <tbody>
              {Object.keys(regTypeCounts).length === 0 ? (
                <tr><td colSpan={3} className="text-sm text-gray-500">No data available. Select events and refresh.</td></tr>
              ) : (
                Object.keys(regTypeCounts).flatMap(evId => {
                  const ev = events.find(e => e.id === evId);
                  const byType = regTypeCounts[evId] || {};
                  const rows = Object.keys(byType);
                  if (rows.length === 0) return [<tr key={evId}><td>{ev?.title || evId}</td><td colSpan={2} className="text-sm text-gray-500">No registrations</td></tr>];
                  return rows.map(type => (
                    <tr key={evId + type}>
                      <td>{ev?.title || evId}</td>
                      <td>{type}</td>
                      <td>{byType[type]}</td>
                    </tr>
                  ));
                })
              )}
            </tbody>
          </table>
        </div>
      </Section>

      <Section
        title="Ticket usage summary (extra)"
        actions={
          <>
            <button className="px-3 py-1.5 text-sm rounded border" onClick={exportUsageCsv}>Export CSV</button>
            <button className="px-3 py-1.5 text-sm rounded border" onClick={printUsage}>Save as PDF</button>
            <button className="px-3 py-1.5 text-sm rounded border" onClick={emailUsage}>Email</button>
          </>
        }
      >
        <div className="overflow-auto">
          <table className="min-w-[420px]">
            <thead>
              <tr>
                <th>Event</th>
                <th>Used</th>
                <th>Unused</th>
              </tr>
            </thead>
            <tbody>
              {Object.keys(ticketUsage).length === 0 ? (
                <tr><td colSpan={3} className="text-sm text-gray-500">No data available. Select events and refresh.</td></tr>
              ) : Object.keys(ticketUsage).map(evId => {
                const ev = events.find(e => e.id === evId);
                const tu = ticketUsage[evId];
                return (
                  <tr key={evId}>
                    <td>{ev?.title || evId}</td>
                    <td>{tu.used}</td>
                    <td>{tu.unused}</td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      </Section>
    </div>
  );
}

function tableHtml(headers: string[], rows: (string | number)[][]) {
  const thead = `<tr>${headers.map(h => `<th>${escapeHtml(h)}</th>`).join('')}</tr>`;
  const tbody = rows.map(r => `<tr>${r.map(c => `<td>${escapeHtml(String(c ?? ''))}</td>`).join('')}</tr>`).join('');
  return `<table><thead>${thead}</thead><tbody>${tbody}</tbody></table>`;
}

function escapeHtml(s: string) {
  return s.replace(/[&<>"']/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c] as string));
}
