/**
 * Per-workspace compute quotas.
 *
 * Why these exist: the platform spawns Coolify projects, Docker
 * containers, and dev VMs in response to AI tool calls. Without a
 * cap, a single bad-actor signup could spin up unbounded resources
 * before we notice — and the GCE bill is the one place where bad
 * actors hit *us* for real money.
 *
 * Quotas are SOFT caps — they return friendly errors with a clear
 * upgrade path. They are NOT a security boundary; auth + tenant
 * isolation are. They are a "don't melt the fleet" control.
 *
 * Numbers are intentionally small for beta. Lift via env vars
 * once we trust the load profile of real users:
 *
 *   VIBN_QUOTA_MAX_PROJECTS_PER_WORKSPACE     (default 3)
 *   VIBN_QUOTA_MAX_DEV_CONTAINERS_PER_WORKSPACE (default 3)
 *
 * To bump for a single power-user, set their workspace's
 * `data.quotaOverrides` jsonb on fs_users — TODO when we have
 * an admin UI; for now, raise the global env var.
 */

import { query } from "@/lib/db-postgres";

export class QuotaExceededError extends Error {
  readonly code = "QUOTA_EXCEEDED";
  readonly resource: string;
  readonly current: number;
  readonly limit: number;

  constructor(
    resource: string,
    current: number,
    limit: number,
    message: string,
  ) {
    super(message);
    this.name = "QuotaExceededError";
    this.resource = resource;
    this.current = current;
    this.limit = limit;
  }
}

const DEFAULT_PROJECT_LIMIT = 9999; // Removed limit for users
const DEFAULT_DEV_CONTAINER_LIMIT = 3;

function projectLimit(): number {
  return DEFAULT_PROJECT_LIMIT; // Removed process.env.VIBN_QUOTA_MAX_PROJECTS_PER_WORKSPACE
}
function devContainerLimit(): number {
  return parsePositiveInt(
    process.env.VIBN_QUOTA_MAX_DEV_CONTAINERS_PER_WORKSPACE,
    DEFAULT_DEV_CONTAINER_LIMIT,
  );
}
function parsePositiveInt(raw: string | undefined, fallback: number): number {
  const n = Number(raw);
  if (Number.isFinite(n) && n > 0) return Math.floor(n);
  return fallback;
}

/**
 * Count active projects for a Vibn workspace and throw
 * QuotaExceededError if creating one more would breach the cap.
 *
 * "Active" = fs_projects.data.status === 'active' (the default for
 * a freshly-created project). Soft-deleted / archived projects are
 * not counted; they don't consume runtime resources.
 *
 * Pass either the workspace UUID (preferred — survives slug changes)
 * or the slug, or both. We'll OR them together so back-compat works
 * for older projects that pre-date the vibn_workspace_id column.
 */
export async function assertProjectQuota(workspace: {
  id?: string | null;
  slug?: string | null;
}): Promise<void> {
  const limit = projectLimit();
  const rows = await query<{ count: string }>(
    `SELECT COUNT(*)::text AS count
       FROM fs_projects
      WHERE (vibn_workspace_id = $1 OR workspace = $2)
        AND COALESCE(data->>'status', 'active') = 'active'`,
    [workspace.id ?? null, workspace.slug ?? null],
  );
  const current = Number(rows[0]?.count ?? 0);
  if (current >= limit) {
    throw new QuotaExceededError(
      "projects",
      current,
      limit,
      `Workspace already has ${current}/${limit} active projects. ` +
        `Delete one or contact support@vibnai.com to lift the cap.`,
    );
  }
}

/**
 * Count running/provisioning dev containers for a workspace and
 * throw if creating one more would breach the cap. Each Vibn
 * project has at most one dev container (project_id is unique
 * key on fs_project_dev_containers), so this functionally caps
 * the number of *projects with active containers*.
 *
 * "Running/provisioning" excludes suspended containers — those
 * cost nothing while idle and resume on demand.
 */
export async function assertDevContainerQuota(
  workspaceSlug: string,
): Promise<void> {
  const limit = devContainerLimit();
  const rows = await query<{ count: string }>(
    `SELECT COUNT(*)::text AS count
       FROM fs_project_dev_containers
      WHERE workspace = $1
        AND state IN ('running', 'provisioning')`,
    [workspaceSlug],
  );
  const current = Number(rows[0]?.count ?? 0);
  if (current >= limit) {
    throw new QuotaExceededError(
      "devContainers",
      current,
      limit,
      `Workspace already has ${current}/${limit} active dev containers running. ` +
        `Suspend an idle one (it'll resume next time you chat with that project) ` +
        `or contact support@vibnai.com to lift the cap.`,
    );
  }
}

/**
 * Read-only quota status for the workspace — used by an admin UI
 * (eventually) and by the AI when explaining limits to users.
 */
export async function getQuotaStatus(workspace: {
  id?: string | null;
  slug?: string | null;
}) {
  const [pRows, cRows] = await Promise.all([
    query<{ count: string }>(
      `SELECT COUNT(*)::text AS count FROM fs_projects
        WHERE (vibn_workspace_id = $1 OR workspace = $2)
          AND COALESCE(data->>'status', 'active') = 'active'`,
      [workspace.id ?? null, workspace.slug ?? null],
    ),
    workspace.slug
      ? query<{ count: string }>(
          `SELECT COUNT(*)::text AS count FROM fs_project_dev_containers
            WHERE workspace = $1 AND state IN ('running', 'provisioning')`,
          [workspace.slug],
        )
      : Promise.resolve([{ count: "0" }]),
  ]);
  return {
    projects: { current: Number(pRows[0]?.count ?? 0), limit: projectLimit() },
    devContainers: {
      current: Number(cRows[0]?.count ?? 0),
      limit: devContainerLimit(),
    },
  };
}
