import type { FastifyPluginAsync } from "fastify";
import { env } from "../env.js";
import { supabase } from "../lib/supabase.js";

type RevenueCatEventType =
  | "INITIAL_PURCHASE"
  | "RENEWAL"
  | "PRODUCT_CHANGE"
  | "CANCELLATION"
  | "UNCANCELLATION"
  | "EXPIRATION"
  | "BILLING_ISSUE"
  | "SUBSCRIBER_ALIAS"
  | "SUBSCRIPTION_PAUSED"
  | "TRANSFER";

interface RevenueCatWebhookEvent {
  type: RevenueCatEventType;
  app_user_id: string;
  product_id: string;
  expiration_at_ms: number | null;
}

const ACTIVE_EVENTS: RevenueCatEventType[] = ["INITIAL_PURCHASE", "RENEWAL", "PRODUCT_CHANGE", "UNCANCELLATION"];
const GRACE_EVENTS: RevenueCatEventType[] = ["BILLING_ISSUE"];
// CANCELLATION means auto-renew was turned off, not that access ended yet —
// the subscription stays active until EXPIRATION actually fires.
const SUSPENDED_EVENTS: RevenueCatEventType[] = ["EXPIRATION"];

export const subscriptionRoutes: FastifyPluginAsync = async (app) => {
  // Mobile app local state is never trusted for entitlement — RevenueCat's
  // webhook, verified here, is the only writer of subscription status (PRD §16).
  app.post("/subscription/webhook", async (req, reply) => {
    const authHeader = req.headers.authorization;
    const expected = env.REVENUECAT_WEBHOOK_SECRET ? `Bearer ${env.REVENUECAT_WEBHOOK_SECRET}` : null;

    if (!expected || authHeader !== expected) {
      return reply.code(401).send({ message: "unauthorized" });
    }

    if (!supabase) return reply.code(500).send({ message: "server misconfigured" });

    const body = req.body as { event?: RevenueCatWebhookEvent };
    const event = body.event;
    if (!event?.app_user_id || !event.type) {
      return reply.code(400).send({ message: "missing event" });
    }

    // app_user_id is the restaurant's id — the mobile app must configure the
    // RevenueCat SDK with Purchases.configure({ appUserID: restaurantId }).
    const restaurantId = event.app_user_id;

    let status: "active" | "grace_period" | "suspended" | null = null;
    if (ACTIVE_EVENTS.includes(event.type)) status = "active";
    else if (GRACE_EVENTS.includes(event.type)) status = "grace_period";
    else if (SUSPENDED_EVENTS.includes(event.type)) status = "suspended";

    if (!status) {
      return reply.send({ received: true });
    }

    const { error } = await supabase.from("subscriptions").upsert(
      {
        restaurant_id: restaurantId,
        status,
        product_id: event.product_id,
        current_period_ends_at: event.expiration_at_ms ? new Date(event.expiration_at_ms).toISOString() : null,
        updated_at: new Date().toISOString(),
      },
      { onConflict: "restaurant_id" },
    );

    if (error) {
      req.log.error(error);
      return reply.code(500).send({ message: "failed to update subscription" });
    }

    return reply.send({ received: true });
  });
};
