/**
 * Org capacity policy service (ADR-0022).
 *
 * Stores per-Organization lower `organizationLimit` overrides per
 * `CapacityDimension`. Enforces the layered-limit invariant: a set limit must be ≤ the
 * platform ceiling for that dimension. The effective limit (min of the two)
 * is the value capacity admission should use; dimensions with no org override
 * fall back to the platform ceiling.
 */
import type { PrismaClient } from "@prisma/client";
import { CAPACITY_DIMENSIONS, isCapacityDimension, type CapacityDimension } from "../capacity/dimensions.js";
import { readPlatformCeilings } from "../capacity/ceilings.js";
import { lockActiveOrganization } from "./status.js";

export interface CapacityPolicyView {
  /** Per-dimension: platform ceiling (absent if not configured) + org limit. */
  readonly dimensions: ReadonlyArray<{
    readonly dimension: CapacityDimension;
    readonly platformCeiling: number | null;
    readonly organizationLimit: number | null;
    readonly effective: number | null;
  }>;
}

export async function getCapacityPolicy(
  prisma: PrismaClient,
  organizationId: string,
): Promise<CapacityPolicyView> {
  const row = await prisma.organizationCapacityPolicy.findUnique({
    where: { organizationId },
    select: { limits: true },
  });
  const orgLimits = parseLimits(row?.limits);
  const ceilings = readPlatformCeilings();
  const dimensions = CAPACITY_DIMENSIONS.map((dimension) => {
    const platformCeiling = ceilings[dimension] ?? null;
    const organizationLimit = orgLimits[dimension] ?? null;
    const effective = effectiveLimit(platformCeiling, organizationLimit);
    return { dimension, platformCeiling, organizationLimit, effective };
  });
  return { dimensions };
}

export async function setCapacityPolicy(
  prisma: PrismaClient,
  input: {
    readonly organizationId: string;
    /** Partial map of dimension → limit. null/absent clears a dimension. */
    readonly limits: Partial<Record<CapacityDimension, number | null>>;
  },
): Promise<CapacityPolicyView> {
  const ceilings = readPlatformCeilings();
  const cleaned: Record<string, number> = {};
  for (const [dimension, value] of Object.entries(input.limits)) {
    if (!isCapacityDimension(dimension)) {
      throw new Error(`unknown capacity dimension: ${dimension}`);
    }
    if (value === null || value === undefined) continue;
    if (!Number.isFinite(value) || value <= 0 || !Number.isInteger(value)) {
      throw new Error(`limit for ${dimension} must be a positive integer`);
    }
    const ceiling = ceilings[dimension];
    if (ceiling === undefined) {
      throw new Error(
        `platform ceiling for ${dimension} is not configured; cannot set an organization limit (spec LayeredLimit.Valid)`,
      );
    }
    if (value > ceiling) {
      throw new Error(
        `organization limit ${value} for ${dimension} exceeds platform ceiling ${ceiling} (spec LayeredLimit.Valid)`,
      );
    }
    cleaned[dimension] = value;
  }

  await prisma.$transaction(async (tx) => {
    await lockActiveOrganization(tx, input.organizationId);
    await tx.organizationCapacityPolicy.upsert({
      where: { organizationId: input.organizationId },
      create: { organizationId: input.organizationId, limits: cleaned },
      update: { limits: cleaned },
    });
  });
  return getCapacityPolicy(prisma, input.organizationId);
}

function effectiveLimit(platformCeiling: number | null, organizationLimit: number | null): number | null {
  if (platformCeiling === null) return null;
  if (organizationLimit === null) return platformCeiling;
  return Math.min(platformCeiling, organizationLimit);
}

function parseLimits(raw: unknown): Partial<Record<CapacityDimension, number>> {
  if (raw === null || typeof raw !== "object") return {};
  const result: Partial<Record<CapacityDimension, number>> = {};
  for (const [key, value] of Object.entries(raw as Record<string, unknown>)) {
    if (isCapacityDimension(key) && typeof value === "number" && Number.isFinite(value)) {
      result[key] = value;
    }
  }
  return result;
}
