import { NextResponse } from "next/server";
import { sql } from "@/db";
import { requireAdmin } from "@/lib/admin-auth";
import { grantPremium, revokeToFree, ENTITLED_STATUSES, TERMINAL_STATUSES } from "@/lib/billing/entitlements";

/**
 * POST /api/admin/reconcile-subscriptions — admin recovery + diagnostic.
 *
 * For each family_subscription, looks at the most recent webhook event we
 * logged for its Razorpay subscription id, derives the intended status, and
 * (re)applies the grant/revoke + row update — catching and RETURNING any error.
 *
 * Why this exists: the webhook logs an event before processing it, so a
 * processing error left the event logged-but-unprocessed and the idempotency
 * guard blocked retries. This endpoint reprocesses those stuck events safely
 * (all grant/revoke ops are idempotent) and surfaces the real error per sub.
 */
const GRANT_FROM_EVENT: Record<string, string> = {
  "subscription.authenticated": "authenticated",
  "subscription.activated": "active",
  "subscription.charged": "active",
  "subscription.resumed": "active",
  "subscription.pending": "pending",
};
const REVOKE_FROM_EVENT: Record<string, string> = {
  "subscription.halted": "halted",
  "subscription.cancelled": "cancelled",
  "subscription.completed": "completed",
  "subscription.expired": "expired",
  "subscription.paused": "paused",
};

export async function POST(request: Request) {
  const auth = await requireAdmin(request);
  if (!auth.success) return NextResponse.json({ error: auth.error }, { status: auth.status });

  const subs = await sql`
    SELECT id, family_id, razorpay_subscription_id, status FROM family_subscriptions
  `;

  const results: unknown[] = [];

  for (const s of subs as Record<string, unknown>[]) {
    const subId = s.razorpay_subscription_id as string;
    const rowId = s.id as string;
    const familyId = s.family_id as string;

    // Most recent webhook event we have for this subscription.
    const ev = await sql`
      SELECT event_type, payload FROM razorpay_webhook_events
      WHERE payload->'payload'->'subscription'->'entity'->>'id' = ${subId}
      ORDER BY received_at DESC
      LIMIT 1
    `;
    const event = ev[0] as { event_type: string; payload: Record<string, unknown> } | undefined;
    if (!event) {
      results.push({ subId, action: "skipped", reason: "no webhook event logged yet" });
      continue;
    }

    const eventType = event.event_type;
    const grant = GRANT_FROM_EVENT[eventType];
    const revoke = REVOKE_FROM_EVENT[eventType];

    try {
      // Pull current_start/current_end from the stored payload.
      const entity = ((event.payload as Record<string, unknown>)?.payload as Record<string, unknown>)
        ?.subscription as Record<string, unknown> | undefined;
      const ent = (entity as { entity?: Record<string, unknown> })?.entity;
      // ISO strings — postgres.js binds timestamps as strings, not Date objects.
      const toISO = (v: unknown) => {
        const n = Number(v);
        return Number.isFinite(n) && n > 0 ? new Date(n * 1000).toISOString() : null;
      };
      const currentStart = toISO(ent?.current_start);
      const currentEnd = toISO(ent?.current_end);
      const customerId = (ent?.customer_id as string) ?? null;

      if (grant) {
        await sql`
          UPDATE family_subscriptions SET
            status               = ${grant}::subscription_status_enum,
            razorpay_customer_id = COALESCE(${customerId}, razorpay_customer_id),
            current_start        = COALESCE(${currentStart}, current_start),
            current_end          = COALESCE(${currentEnd}, current_end),
            updated_at           = NOW()
          WHERE id = ${rowId}
        `;
        await grantPremium(familyId, grant);
        results.push({ subId, familyId, eventType, applied: "grant", status: grant, ok: true });
      } else if (revoke) {
        await sql`
          UPDATE family_subscriptions SET
            status     = ${revoke}::subscription_status_enum,
            updated_at = NOW()
          WHERE id = ${rowId}
        `;
        await revokeToFree(familyId, revoke);
        results.push({ subId, familyId, eventType, applied: "revoke", status: revoke, ok: true });
      } else {
        results.push({ subId, eventType, action: "skipped", reason: "unhandled event type" });
      }
    } catch (e) {
      results.push({ subId, familyId, eventType, ok: false, error: String(e) });
    }
  }

  // Show resulting family tiers so we can confirm the grant landed.
  const families = await sql`
    SELECT id, tier, subscription_status, max_members, max_children
    FROM families WHERE tier != 'free' OR subscription_status IS NOT NULL
  `;

  return NextResponse.json({
    success: true,
    reconciled: results,
    paidFamilies: families,
    entitledStatuses: [...ENTITLED_STATUSES],
    terminalStatuses: [...TERMINAL_STATUSES],
  });
}
