/**
 * Entitlement queries.
 *
 * Two versions:
 *   - getEntitlementsForUser (public query): for frontend ConvexClient subscription.
 *     Derives the subject from Convex auth and returns free-tier defaults when
 *     unauthenticated.
 *   - getEntitlementsByUserId (internal query): for the gateway ConvexHttpClient
 *     cache-miss fallback. Trusted server-to-server call with no auth gap.
 */

import type { QueryCtx } from "./_generated/server";
import { query, internalQuery } from "./_generated/server";
import { v } from "convex/values";
import { getFeaturesForPlan } from "./lib/entitlements";
import { resolveUserId } from "./lib/auth";

const FREE_TIER_DEFAULTS = {
  planKey: "free" as const,
  features: getFeaturesForPlan("free"),
  validUntil: 0,
};

/** Shared handler logic for both public and internal queries. */
async function getEntitlementsHandler(
  ctx: QueryCtx,
  userId: string,
) {
  const entitlement = await ctx.db
    .query("entitlements")
    .withIndex("by_userId", (q) => q.eq("userId", userId))
    .first();

  if (!entitlement) {
    return FREE_TIER_DEFAULTS;
  }

  // Expired entitlements fall back to free tier (Pitfall 7 from research)
  if (entitlement.validUntil < Date.now()) {
    return FREE_TIER_DEFAULTS;
  }

  // Read-time merge with the canonical product catalog so feature flags added
  // to PRODUCT_CATALOG since the row was last written by the Dodo webhook
  // are surfaced immediately — no need to wait for the next subscription
  // event to rewrite the row. Stored row's `features` win on conflict
  // (preserves any per-user overrides). New fields the row lacks (e.g.
  // `mcpAccess` post-plan-2026-05-10-001 U10) inherit the catalog default
  // for the user's plan.
  const catalogDefaults = getFeaturesForPlan(entitlement.planKey);
  return {
    planKey: entitlement.planKey,
    features: { ...catalogDefaults, ...entitlement.features },
    validUntil: entitlement.validUntil,
  };
}

/**
 * Public query: returns entitlements for the authenticated user.
 *
 * Derives the caller from server-side auth identity. Unauthenticated
 * callers get free-tier defaults instead of arbitrary cross-user reads.
 */
export const getEntitlementsForUser = query({
  args: {},
  handler: async (ctx) => {
    const userId = await resolveUserId(ctx);
    if (!userId) {
      return FREE_TIER_DEFAULTS;
    }
    return getEntitlementsHandler(ctx, userId);
  },
});

/**
 * Internal query: returns entitlements for a given userId.
 *
 * Used by the gateway ConvexHttpClient for cache-miss fallback.
 * Trusted server-to-server call — no auth gap.
 */
export const getEntitlementsByUserId = internalQuery({
  args: { userId: v.string() },
  handler: async (ctx, args) => {
    return getEntitlementsHandler(ctx, args.userId);
  },
});
