import { assert } from "../../shared/src/asserts.js";
import { toStaticParam, mapCondition } from "../../zero-protocol/src/ast.js";
import { newExpressionBuilder } from "../../zql/src/query/static-query.js";
import { clientToServer } from "./name-mapper.js";
const ANYONE_CAN = [
  (_, eb) => eb.and()
];
const ANYONE_CAN_DO_ANYTHING = {
  row: {
    select: ANYONE_CAN,
    insert: ANYONE_CAN,
    update: {
      preMutation: ANYONE_CAN,
      postMutation: ANYONE_CAN
    },
    delete: ANYONE_CAN
  }
};
const NOBODY_CAN = [];
async function definePermissions(schema, definer) {
  const expressionBuilders = {};
  for (const name of Object.keys(schema.tables)) {
    expressionBuilders[name] = newExpressionBuilder(schema, name);
  }
  const config = await definer();
  return compilePermissions(schema, config, expressionBuilders);
}
function compilePermissions(schema, authz, expressionBuilders) {
  if (!authz) {
    return void 0;
  }
  const nameMapper = clientToServer(schema.tables);
  const ret = { tables: {} };
  for (const [tableName, tableConfig] of Object.entries(authz)) {
    const serverName = schema.tables[tableName].serverName ?? tableName;
    ret.tables[serverName] = {
      row: compileRowConfig(
        nameMapper,
        tableName,
        tableConfig.row,
        expressionBuilders[tableName]
      ),
      cell: compileCellConfig(
        nameMapper,
        tableName,
        tableConfig.cell,
        expressionBuilders[tableName]
      )
    };
  }
  return ret;
}
function compileRowConfig(clientToServer2, tableName, rowRules, expressionBuilder) {
  if (!rowRules) {
    return void 0;
  }
  return {
    select: compileRules(
      clientToServer2,
      tableName,
      rowRules.select,
      expressionBuilder
    ),
    insert: compileRules(
      clientToServer2,
      tableName,
      rowRules.insert,
      expressionBuilder
    ),
    update: {
      preMutation: compileRules(
        clientToServer2,
        tableName,
        rowRules.update?.preMutation,
        expressionBuilder
      ),
      postMutation: compileRules(
        clientToServer2,
        tableName,
        rowRules.update?.postMutation,
        expressionBuilder
      )
    },
    delete: compileRules(
      clientToServer2,
      tableName,
      rowRules.delete,
      expressionBuilder
    )
  };
}
function compileRules(clientToServer2, tableName, rules, expressionBuilder) {
  if (!rules) {
    return void 0;
  }
  return rules.map((rule) => {
    const cond = rule(authDataRef, expressionBuilder);
    return ["allow", mapCondition(cond, tableName, clientToServer2)];
  });
}
function compileCellConfig(clientToServer2, tableName, cellRules, expressionBuilder) {
  if (!cellRules) {
    return void 0;
  }
  const ret = {};
  for (const [columnName, rules] of Object.entries(cellRules)) {
    ret[columnName] = {
      select: compileRules(
        clientToServer2,
        tableName,
        rules.select,
        expressionBuilder
      ),
      insert: compileRules(
        clientToServer2,
        tableName,
        rules.insert,
        expressionBuilder
      ),
      update: {
        preMutation: compileRules(
          clientToServer2,
          tableName,
          rules.update?.preMutation,
          expressionBuilder
        ),
        postMutation: compileRules(
          clientToServer2,
          tableName,
          rules.update?.postMutation,
          expressionBuilder
        )
      },
      delete: compileRules(
        clientToServer2,
        tableName,
        rules.delete,
        expressionBuilder
      )
    };
  }
  return ret;
}
class CallTracker {
  #anchor;
  #path;
  constructor(anchor, path) {
    this.#anchor = anchor;
    this.#path = path;
  }
  get(target, prop) {
    if (prop === toStaticParam) {
      return target[toStaticParam];
    }
    assert(typeof prop === "string");
    const path = [...this.#path, prop];
    return new Proxy(
      {
        [toStaticParam]: () => staticParam(this.#anchor, path)
      },
      new CallTracker(this.#anchor, path)
    );
  }
}
function baseTracker(anchor) {
  return new Proxy(
    {
      [toStaticParam]: () => {
        throw new Error("no JWT field specified");
      }
    },
    new CallTracker(anchor, [])
  );
}
const authDataRef = baseTracker("authData");
baseTracker("preMutationRow");
function staticParam(anchorClass, field) {
  return {
    type: "static",
    anchor: anchorClass,
    // for backwards compatibility
    field: field.length === 1 ? field[0] : field
  };
}
export {
  ANYONE_CAN,
  ANYONE_CAN_DO_ANYTHING,
  NOBODY_CAN,
  authDataRef,
  definePermissions,
  staticParam
};
//# sourceMappingURL=permissions.js.map
