import { readFileSync } from "node:fs";
import { Lexicons, jsonToLex, type LexiconDoc } from "@atproto/lexicon";

// Validate against the lexicon JSON documents directly (the same source the
// generated lib/lexicons code is built from). PDSes don't reliably enforce
// third-party lexicons, so validating is the indexer's responsibility.
const loadDoc = (path: string): LexiconDoc =>
  JSON.parse(readFileSync(new URL(`../../lexicons/${path}`, import.meta.url), "utf8"));

const lexicons = new Lexicons([
  loadDoc("app/sidetrail/trail.json"),
  loadDoc("app/sidetrail/walk.json"),
  loadDoc("app/sidetrail/completion.json"),
  loadDoc("com/atproto/repo/strongRef.json"),
]);

export const INDEXED_COLLECTIONS = [
  "app.sidetrail.trail",
  "app.sidetrail.walk",
  "app.sidetrail.completion",
] as const;

export type IndexedCollection = (typeof INDEXED_COLLECTIONS)[number];

export function validateRecord(
  collection: IndexedCollection,
  record: unknown,
): { success: true } | { success: false; reason: string } {
  // Records arrive as JSON (jetstream, listRecords, jsonb storage), where CID
  // links are {"$link": ...} objects. The validator expects lex values, so
  // convert first; a record that can't be converted (e.g. malformed CID) is invalid.
  let lexValue: unknown;
  try {
    lexValue = jsonToLex(record);
  } catch (err) {
    return { success: false, reason: `unparseable as lex: ${(err as Error).message}` };
  }
  const result = lexicons.validate(collection, lexValue);
  if (result.success) return { success: true };
  return { success: false, reason: result.error.message };
}
