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, getActiveHouseholdId } from "./helpers.js";
import { errors } from "./errors.js";

/** Vem "äger" kvoten? Hela hushållet delar ägarens plan + pott.
 * Ensam användare = sig själv (äger sitt eget hushåll). */
async function billingUserFor(db: Database, userId: string): Promise<string> {
  const householdId = await getActiveHouseholdId(db, userId);
  if (!householdId) return userId;
  const [owner] = await db
    .select({ userId: schema.householdMembers.userId })
    .from(schema.householdMembers)
    .where(
      and(
        eq(schema.householdMembers.householdId, householdId),
        eq(schema.householdMembers.role, "owner"),
      ),
    )
    .limit(1);
  return owner?.userId ?? userId;
}

/** 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 billingUserId = await billingUserFor(db, userId);
  const [subRow] = await db
    .select()
    .from(schema.subscriptions)
    .where(eq(schema.subscriptions.userId, billingUserId))
    .orderBy(desc(schema.subscriptions.updatedAt))
    .limit(1);

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

  const [usageRow] = await db
    .select()
    .from(schema.aiUsageCounters)
    .where(
      and(
        eq(schema.aiUsageCounters.userId, billingUserId),
        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. */
/**
 * Dra AI-skanningskvot. `units` = antal bilder i skanningen (spec §45–46):
 * en skanning debiteras per bild, så 6 foton = 6 enheter. Blockerar om hela
 * skanningen inte får plats i kvarvarande kvot (allt-eller-inget – appen kapar
 * antalet foton till kvarvarande kvot så det aldrig blockeras mitt i flödet).
 */
export async function consumeAiScan(db: Database, userId: string, units = 1): Promise<void> {
  const count = Math.max(1, Math.floor(units));
  const billingUserId = await billingUserFor(db, userId);
  const ent = await loadEntitlements(db, billingUserId);
  if (ent.aiScansUsedThisMonth + count > ent.aiScansPerMonth) {
    const kvar = Math.max(0, ent.aiScansPerMonth - ent.aiScansUsedThisMonth);
    throw errors.quotaExceeded(
      `Månadens AI-skanningar räcker inte (${kvar} kvar av ${ent.aiScansPerMonth}, den här kräver ${count}). Uppgradera för fler.`,
    );
  }
  const month = currentMonth();
  const { sql } = await import("drizzle-orm");
  await db
    .insert(schema.aiUsageCounters)
    .values({ userId: billingUserId, month, aiScans: count })
    .onConflictDoUpdate({
      target: [schema.aiUsageCounters.userId, schema.aiUsageCounters.month],
      set: { aiScans: sql`${schema.aiUsageCounters.aiScans} + ${count}` },
    });
}

/** 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.`,
    );
  }
}
