import { notFound, redirect } from "next/navigation";
import { and, asc, desc, eq, gte } from "drizzle-orm";
import { db } from "@db/client";
import { events, ticketTypes, orders, tickets, eventLinks } from "@db/schema";
import { getDashboardUser } from "@/lib/view-as";
import { getCategories } from "@db/queries/categories";
import { getOrganizerSettlement } from "@db/queries/settlement";
import {
  getLatestResolvedCancellationForEvent,
  getPendingCancellationForEvent,
} from "@db/queries/cancellations";
import { formatPrice, nowMs } from "@/lib/format";
import { format } from "date-fns";
import EventStatusToggle from "./event-status-toggle";
import TicketTypeForm from "./ticket-type-form";
import CompTicketForm from "./comp-ticket-form";
import DeleteTicketTypeButton from "./delete-ticket-type-button";
import TicketTypeControls from "./ticket-type-controls";
import ExportCsvButton from "./export-csv-button";
import CopyEventLinkButton from "./copy-event-link-button";
import EventDetailsForm from "./event-details-form";
import EventLinksManager, { type AdminEventLink } from "./event-links-manager";
import { SalesOverTimeChart, HorizontalBarBreakdown } from "./charts";
import BuyersTable, { type BuyerOrder } from "./buyers-table";
import type { EventRow } from "@/lib/types";

export default async function ManageEventPage({
  params,
}: {
  params: Promise<{ id: string }>;
}) {
  const { id } = await params;
  const { user, viewingAs } = await getDashboardUser();
  if (!user) redirect("/login");

  // Scope to the owner: there's no RLS backstop anymore, so this filter is
  // what keeps one organizer out of another's management page.
  const [eventRow] = await db
    .select()
    .from(events)
    .where(and(eq(events.id, id), eq(events.organizerId, user.id)))
    .limit(1);
  if (!eventRow) notFound();

  const sevenDaysAgo = new Date(nowMs() - 7 * 24 * 60 * 60 * 1000);
  const [tierRows, paidOrders, ticketRows, categories, links, pendingOrders] = await Promise.all([
    db.select().from(ticketTypes).where(eq(ticketTypes.eventId, id)).orderBy(asc(ticketTypes.createdAt)),
    db.select().from(orders).where(and(eq(orders.eventId, id), eq(orders.status, "paid"))).orderBy(desc(orders.createdAt)),
    db.select().from(tickets).where(eq(tickets.eventId, id)),
    getCategories(),
    db
      .select({ id: eventLinks.id, label: eventLinks.label, url: eventLinks.url, kind: eventLinks.kind, sortOrder: eventLinks.sortOrder })
      .from(eventLinks)
      .where(eq(eventLinks.eventId, id))
      .orderBy(asc(eventLinks.sortOrder)),
    // "Incoming" buyers: started checkout recently but not (yet) paid.
    db
      .select()
      .from(orders)
      .where(and(eq(orders.eventId, id), eq(orders.status, "pending"), gte(orders.createdAt, sevenDaysAgo)))
      .orderBy(desc(orders.createdAt))
      .limit(300),
  ]);

  // (No refund-request data: organizers can't request refunds from here --
  // removed at the client's request; refunds are admin-only.)
  const [pendingCancellation, lastResolvedCancellation, settlement] = await Promise.all([
    getPendingCancellationForEvent(id),
    getLatestResolvedCancellationForEvent(id),
    getOrganizerSettlement(user.id),
  ]);

  const currency = tierRows[0]?.currency ?? "kes";
  // One "now" for every ticket type's open/closed status on this render.
  const renderedAt = nowMs();
  const totalRevenueCents = paidOrders.reduce((sum, o) => sum + o.totalCents, 0);
  const ticketsSold = paidOrders.length ? tierRows.reduce((sum, tt) => sum + tt.quantitySold, 0) : 0;
  const checkedInCount = ticketRows.filter((t) => t.status === "used").length;
  // Same calculation as payouts and admin earnings (db/queries/settlement.ts):
  // commission, its tax and this event's email/SMS charges.
  const netPayoutCents = settlement?.events.find((e) => e.event_id === id)?.net_cents ?? totalRevenueCents;

  const byDay = new Map<string, number>();
  for (const o of paidOrders) {
    const day = format(o.createdAt, "MMM d");
    byDay.set(day, (byDay.get(day) ?? 0) + o.totalCents);
  }
  const salesOverTime = Array.from(byDay.entries())
    .reverse()
    .map(([label, cents]) => ({ label, cents }));

  const byTier = tierRows.map((tt) => ({ label: tt.name, value: tt.quantitySold }));

  const byMethod = new Map<string, number>();
  for (const o of paidOrders) {
    byMethod.set(o.paymentMethod, (byMethod.get(o.paymentMethod) ?? 0) + 1);
  }
  const PAYMENT_METHOD_LABEL: Record<string, string> = {
    mpesa: "M-Pesa",
    card: "Card",
    paypal: "PayPal",
    comp: "Comp",
  };
  const paymentBreakdown = Array.from(byMethod.entries()).map(([label, count]) => ({
    label: PAYMENT_METHOD_LABEL[label] ?? label,
    value: count,
    sublabel: `${Math.round((count / Math.max(paidOrders.length, 1)) * 100)}%`,
  }));

  // EventDetailsForm expects the snake_case EventRow shape (src/lib/types.ts),
  // same convention every db/queries/* module maps to.
  // No fee_bps: it would ride along to the browser, and the fee is admin-only.
  const eventForForm: Omit<EventRow, "fee_bps"> = {
    id: eventRow.id,
    organizer_id: eventRow.organizerId,
    title: eventRow.title,
    description: eventRow.description,
    venue: eventRow.venue,
    city: eventRow.city,
    organizer_name: eventRow.organizerName,
    organizer_phone: eventRow.organizerPhone,
    organizer_email: eventRow.organizerEmail,
    age_restriction: eventRow.ageRestriction,
    starts_at: eventRow.startsAt.toISOString(),
    ends_at: eventRow.endsAt ? eventRow.endsAt.toISOString() : null,
    cover_image_url: eventRow.coverImageUrl,
    category_id: eventRow.categoryId,
    status: eventRow.status,
    featured: eventRow.featured,
    slug: eventRow.slug,
    created_at: eventRow.createdAt.toISOString(),
  };

  // Buyers table rows (contacts + per-order tickets for cancel-for-upgrade).
  const tierById = new Map(tierRows.map((tt) => [tt.id, tt]));
  const ticketsByOrder = new Map<string, typeof ticketRows>();
  for (const t of ticketRows) {
    const list = ticketsByOrder.get(t.orderId) ?? [];
    list.push(t);
    ticketsByOrder.set(t.orderId, list);
  }
  const buyerRows = (list: typeof paidOrders): BuyerOrder[] =>
    list.map((o) => ({
      id: o.id,
      name: o.buyerName,
      email: o.buyerEmail,
      phone: o.buyerPhone,
      createdAt: o.createdAt.toISOString(),
      method: PAYMENT_METHOD_LABEL[o.paymentMethod] ?? o.paymentMethod,
      total: formatPrice(o.totalCents, o.currency),
      status: o.status === "paid" ? "paid" : "pending",
      tickets: (ticketsByOrder.get(o.id) ?? []).map((t) => ({
        id: t.id,
        code: t.code,
        typeName: tierById.get(t.ticketTypeId)?.name ?? "Ticket",
        status: t.status,
        admitsCount: tierById.get(t.ticketTypeId)?.admitsCount ?? 1,
      })),
    }));

  return (
    <div className="space-y-8">
      <div className="flex items-start justify-between">
        <div>
          <h1 className="text-2xl font-semibold">{eventRow.title}</h1>
          <p className="text-sm text-be-muted">{eventRow.venue}</p>
        </div>
        <div className="flex gap-2">
          <CopyEventLinkButton
            eventId={eventRow.id}
            eventTitle={eventRow.title}
            eventSlug={eventRow.slug}
            startsAt={eventRow.startsAt.toISOString()}
          />
          <ExportCsvButton eventId={eventRow.id} />
          <EventStatusToggle
            eventId={eventRow.id}
            status={eventRow.status}
            approvalStatus={eventRow.approvalStatus}
            approvalNote={eventRow.approvalNote}
            pendingCancellation={
              pendingCancellation
                ? { reason: pendingCancellation.reason, createdAt: pendingCancellation.created_at }
                : null
            }
            lastRejection={
              lastResolvedCancellation?.status === "rejected"
                ? { note: lastResolvedCancellation.resolution_note }
                : null
            }
          />
        </div>
      </div>

      <section className="grid grid-cols-2 sm:grid-cols-4 gap-3">
        <StatCard label="Tickets sold" value={ticketsSold.toString()} />
        <StatCard label="Gross revenue" value={formatPrice(totalRevenueCents, currency)} />
        <StatCard label="Checked in" value={checkedInCount.toString()} />
        <StatCard label="Net payout" value={formatPrice(netPayoutCents, currency)} />
      </section>

      <section className="grid sm:grid-cols-2 gap-6">
        <div className="rounded-lg border border-be-border bg-be-surface p-4">
          <h2 className="text-sm font-medium mb-3">Sales over time</h2>
          <SalesOverTimeChart data={salesOverTime} />
        </div>
        <div className="rounded-lg border border-be-border bg-be-surface p-4">
          <h2 className="text-sm font-medium mb-3">Tickets by tier</h2>
          <HorizontalBarBreakdown data={byTier} />
        </div>
      </section>

      <section className="grid sm:grid-cols-2 gap-6">
        <div className="rounded-lg border border-be-border bg-be-surface p-4">
          <h2 className="text-sm font-medium mb-3">Payments by method</h2>
          {paymentBreakdown.length ? (
            <HorizontalBarBreakdown data={paymentBreakdown} />
          ) : (
            <p className="text-sm text-be-muted">No paid orders yet.</p>
          )}
        </div>
        <div className="rounded-lg border border-be-border bg-be-surface p-4">
          <h2 className="text-sm font-medium mb-3">Settlement</h2>
          {/* Organizers see the cash they receive, not the fee breakdown --
              that's admin-only (see /admin/earnings). */}
          <p className="text-sm text-be-muted">
            Your payout: <span className="font-semibold text-be-text">{formatPrice(netPayoutCents, currency)}</span>
          </p>
          <p className="text-xs text-be-muted mt-2">
            M-Pesa orders settle via Daraja; card orders settle via Paystack payouts.
          </p>
        </div>
      </section>

      <section>
        <h2 className="text-lg font-medium mb-1">Buyers</h2>
        <p className="text-sm text-be-muted mb-3">
          Everyone who bought a ticket, with their phone and email. Open a buyer to see their tickets
          or cancel one so they can upgrade (e.g. Regular → VIP/VVIP).
        </p>
        <BuyersTable paid={buyerRows(paidOrders)} pending={buyerRows(pendingOrders)} canEdit={!viewingAs} />
      </section>

      <section>
        <h2 className="text-lg font-medium mb-3">Event details</h2>
        <EventDetailsForm event={eventForForm} categories={categories} />
      </section>

      <section>
        <h2 className="text-lg font-medium mb-1">Event links</h2>
        <p className="text-sm text-be-muted mb-3">
          External links shown on the past-event gallery — full Drive/Dropbox gallery, aftermovie,
          press coverage.
        </p>
        <EventLinksManager eventId={eventRow.id} initial={links.map((l) => ({ ...l, sort_order: l.sortOrder }) as AdminEventLink)} />
      </section>

      <section>
        <h2 className="text-lg font-medium mb-3">Ticket types</h2>
        <div className="grid gap-2 mb-4">
          {tierRows.map((tt) => (
            <div
              key={tt.id}
              className="flex items-start justify-between gap-3 rounded-lg border border-be-border bg-be-surface p-3"
            >
              <div>
                <p className="font-medium text-sm">{tt.name}</p>
                <p className="text-xs text-be-muted">
                  {tt.admitsCount > 1 && <>Group of {tt.admitsCount} · </>}
                  {formatPrice(tt.priceCents, tt.currency)} · {tt.quantitySold}/{tt.quantityTotal}{" "}
                  {tt.admitsCount > 1 ? "groups" : ""} sold
                </p>
                <div className="mt-1">
                  <DeleteTicketTypeButton id={tt.id} />
                </div>
              </div>
              <TicketTypeControls
                id={tt.id}
                quantityTotal={tt.quantityTotal}
                quantitySold={tt.quantitySold}
                salesClosed={tt.salesClosed}
                salesEndAt={tt.salesEndAt ? tt.salesEndAt.toISOString() : null}
                nowMs={renderedAt}
              />
            </div>
          ))}
          {!tierRows.length && <p className="text-sm text-be-muted">No ticket types yet.</p>}
        </div>
        <TicketTypeForm eventId={eventRow.id} />
      </section>

      <section>
        <h2 className="text-lg font-medium mb-1">Complimentary tickets</h2>
        <p className="text-sm text-be-muted mb-3">
          Issue a free ticket straight to someone&apos;s inbox — media, sponsors, guests. Skips
          payment entirely but still counts against ticket-type inventory and check-in stats.
        </p>
        <CompTicketForm eventId={eventRow.id} ticketTypes={tierRows.map((tt) => ({ id: tt.id, name: tt.name }))} />
      </section>
    </div>
  );
}

function StatCard({ label, value }: { label: string; value: string }) {
  return (
    <div className="rounded-lg border border-be-border bg-be-surface p-4">
      <p className="text-xs text-be-muted">{label}</p>
      <p className="text-xl font-semibold mt-1">{value}</p>
    </div>
  );
}
