import { and, desc, eq } from "drizzle-orm";
import type { FastifyInstance } from "fastify";
import { schema, type Database } from "@app/database";
import type { Entitlements } from "@app/shared-types";
import {
  computeEntitlements,
  signEntitlementToken,
  type SubscriptionSnapshot,
  type TrialSnapshot,
} from "@app/subscriptions";
import { currentMonth } from "./helpers.js";
import { errors } from "./errors.js";

/** Ladda och beräkna entitlements för en användare. Backend = source of truth (spec §61.14). */
export async function loadEntitlements(db: Database, userId: string): Promise<Entitlements> {
  const [subRow] = await db
    .select()
    .from(schema.subscriptions)
    .where(eq(schema.subscriptions.userId, userId))
    .orderBy(desc(schema.subscriptions.updatedAt))
    .limit(1);

  const [trialRow] = await db
    .select()
    .from(schema.trials)
    .where(eq(schema.trials.userId, userId))
    .limit(1);

  const [usageRow] = await db
    .select()
    .from(schema.aiUsageCounters)
    .where(
      and(
        eq(schema.aiUsageCounters.userId, userId),
        eq(schema.aiUsageCounters.month, currentMonth()),
      ),
    )
    .limit(1);

  const subscription: SubscriptionSnapshot | null = subRow
    ? {
        plan: subRow.plan,
        status: subRow.status,
        expiresAt: subRow.expiresAt,
        gracePeriodExpiresAt: subRow.gracePeriodExpiresAt,
      }
    : null;
  const trial: TrialSnapshot | null = trialRow
    ? { startedAt: trialRow.startedAt, endsAt: trialRow.endsAt }
    : null;

  return computeEntitlements(subscription, trial, {
    aiScansUsedThisMonth: usageRow?.aiScans ?? 0,
  });
}

/** Entitlements + signerad offline-token (spec §44). */
export async function loadEntitlementsWithToken(
  app: FastifyInstance,
  userId: string,
): Promise<Entitlements> {
  const ent = await loadEntitlements(app.db, userId);
  ent.signedToken = signEntitlementToken(userId, ent, app.config.ENTITLEMENT_SIGNING_SECRET, {
    ttlHours: app.config.ENTITLEMENT_TTL_HOURS,
    graceDays: app.config.ENTITLEMENT_GRACE_DAYS,
  });
  return ent;
}

/** Kräv AI-kvot och räkna upp användningen atomiskt. */
export async function consumeAiScan(db: Database, userId: string): Promise<void> {
  const ent = await loadEntitlements(db, userId);
  if (ent.aiScansUsedThisMonth >= ent.aiScansPerMonth) {
    throw errors.quotaExceeded(
      `Månadens AI-skanningar är slut (${ent.aiScansPerMonth} st). Uppgradera för fler.`,
    );
  }
  const month = currentMonth();
  await db
    .insert(schema.aiUsageCounters)
    .values({ userId, month, aiScans: 1 })
    .onConflictDoUpdate({
      target: [schema.aiUsageCounters.userId, schema.aiUsageCounters.month],
      set: { aiScans: (await import("drizzle-orm")).sql`${schema.aiUsageCounters.aiScans} + 1` },
    });
}

/** Kräv en premiumfunktion (t.ex. veckoplanering). */
export async function requireFeature(
  db: Database,
  userId: string,
  feature: "weekPlanning" | "advancedNutrition" | "communityPublish",
  labelSv: string,
): Promise<void> {
  const ent = await loadEntitlements(db, userId);
  if (!ent[feature]) {
    throw errors.paymentRequired(
      `${labelSv} ingår i Premium. Starta din provperiod eller uppgradera.`,
    );
  }
}
