/**
 * Read-only Prisma proxy.
 *
 * Wraps a PrismaClient and blocks write operations at the application level.
 * Used to enforce read-only access for AI read-tools (EGAI 4.1.1.2 / IAAI 3.6.22).
 */

import type { prisma } from "@capakraken/db";

type PrismaClient = typeof prisma;

const WRITE_METHODS = new Set([
  "create",
  "createMany",
  "createManyAndReturn",
  "update",
  "updateMany",
  "upsert",
  "delete",
  "deleteMany",
]);

// Client-level raw/escape hatches that MUST be blocked on a read-only
// context. Missing any one of these lets a read-tool smuggle writes via
// raw SQL, transactions, or the Mongo-style runCommandRaw.
const BLOCKED_CLIENT_METHODS = new Set([
  "$executeRaw",
  "$executeRawUnsafe",
  "$transaction",
  "$queryRawUnsafe",
  "$runCommandRaw",
]);

function readOnlyModelProxy(model: Record<string, unknown>, modelName: string): unknown {
  return new Proxy(model, {
    get(target, prop) {
      if (typeof prop === "string" && WRITE_METHODS.has(prop)) {
        return () => {
          throw new Error(
            `Write operation "${prop}" on "${modelName}" not permitted on read-only context`,
          );
        };
      }
      return Reflect.get(target, prop);
    },
  });
}

export function createReadOnlyProxy(client: PrismaClient): PrismaClient {
  return new Proxy(client, {
    get(target, prop) {
      const value = Reflect.get(target, prop);
      // If accessing a model delegate (object with findMany, etc.), wrap it
      if (value && typeof value === "object" && "findMany" in (value as Record<string, unknown>)) {
        return readOnlyModelProxy(value as Record<string, unknown>, String(prop));
      }
      // Block raw/escape-hatch methods at the client level. $queryRaw
      // (template-tagged) is allowed — it's read-only by API contract;
      // $queryRawUnsafe is blocked because a crafted string could be
      // used to smuggle DDL/DML.
      if (typeof prop === "string" && BLOCKED_CLIENT_METHODS.has(prop)) {
        return () => {
          throw new Error(
            `Raw/escape operation "${String(prop)}" not permitted on read-only context`,
          );
        };
      }
      return value;
    },
  }) as PrismaClient;
}
