import { describe, test, beforeEach, afterEach } from "node:test";
import assert from "node:assert/strict";
import { mkdtempSync, rmSync, existsSync, readFileSync, readdirSync } from "node:fs";
import { join } from "node:path";
import { tmpdir } from "node:os";

import { initBrain } from "../src/scaffold.js";
import { parseProfile } from "../src/profile.js";

/**
 * OKF-compatible-form conformance for the `brain/` knowledge bundle.
 *
 * Stage 1 of the cross-plugin OKF convergence (docs/okf-convergence-brief.md): the
 * brain is the REFERENCE design, OKF is a thin interop veneer. Contract — mirrors
 * `okr/scripts/okf-check.mjs`, the reference checker:
 *   - every CONCEPT file (`*.md` except `index.md`) carries a non-empty `type` in a
 *     leading YAML frontmatter block;
 *   - the bundle-root `index.md` carries an `okf_version` marker as markdown TEXT
 *     (index files carry no frontmatter per the OKF spec);
 *   - each directory level has its own `index.md` (progressive disclosure).
 *
 * EXCLUDED by design (brief §6): the `ingest/` tributary. `ingest/published/*.md`
 * is the byte-exact gold store with a hard round-trip invariant (SC2) that a YAML
 * frontmatter block would break — it is a raw tributary, not a navigable concept,
 * and the hub `index.md` points to it rather than folding it in. This test walks
 * `brain/` ONLY; it never asserts frontmatter on the tributary.
 */

/**
 * Minimal frontmatter `type` reader. We only ever EMIT OKF frontmatter; we never add
 * a YAML-parser dependency (the brain is deliberately YAML-free), so a constrained
 * regex over the leading `---` block is the right reader here.
 */
function frontmatterType(text: string): string | null {
  const block = text.match(/^---\n([\s\S]*?)\n---\n/);
  if (!block) return null;
  const t = block[1].match(/^type:\s*(.+?)\s*$/m);
  return t ? t[1].trim() : null;
}

/** All concept files (`*.md` except `index.md`) under `root`, recursive. */
function walkConceptMd(root: string): string[] {
  const out: string[] = [];
  const walk = (dir: string) => {
    for (const e of readdirSync(dir, { withFileTypes: true })) {
      const p = join(dir, e.name);
      if (e.isDirectory()) walk(p);
      else if (e.isFile() && e.name.endsWith(".md") && e.name !== "index.md") out.push(p);
    }
  };
  walk(root);
  return out;
}

describe("brain/ bundle is OKF-compatible form (Stage 1)", () => {
  let root: string;
  const prevEnv = process.env.LINKEDIN_STUDIO_DATA;

  beforeEach(() => {
    root = mkdtempSync(join(tmpdir(), "brain-okf-"));
    process.env.LINKEDIN_STUDIO_DATA = root;
    initBrain();
  });

  afterEach(() => {
    if (prevEnv === undefined) delete process.env.LINKEDIN_STUDIO_DATA;
    else process.env.LINKEDIN_STUDIO_DATA = prevEnv;
    rmSync(root, { recursive: true, force: true });
  });

  test("bundle-root index.md carries an okf_version marker (markdown text, no frontmatter)", () => {
    const index = readFileSync(join(root, "brain/index.md"), "utf8");
    assert.match(index, /^okf_version:\s*\S+/m, "root index.md declares okf_version");
    assert.equal(frontmatterType(index), null, "index.md carries NO frontmatter (OKF reserved file)");
  });

  test("every concept file under brain/ carries a non-empty frontmatter type", () => {
    const concepts = walkConceptMd(join(root, "brain"));
    assert.ok(concepts.length > 0, "the bundle has concept files to check");
    for (const f of concepts) {
      const type = frontmatterType(readFileSync(f, "utf8"));
      assert.ok(type && type.length > 0, `concept ${f} is missing a frontmatter type:`);
    }
  });

  test("profile.md is type: Profile AND still parses (rich fields preserved — round-trip intact)", () => {
    const text = readFileSync(join(root, "brain/profile.md"), "utf8");
    assert.equal(frontmatterType(text), "Profile");
    const doc = parseProfile(text);
    assert.equal(doc.schemaVersion, 1, "line-grammar still parses through the frontmatter");
    assert.ok(doc.static.length > 0, "the seeded static facts survive conformance");
  });

  test("operations.md is type: Operations", () => {
    const text = readFileSync(join(root, "brain/operations.md"), "utf8");
    assert.equal(frontmatterType(text), "Operations");
  });

  test("concept files carry the cheap recommended fields (title + description)", () => {
    // OKF recommends title/description; they are free (constant) here and give a
    // foreign agent a human label without a clock (timestamp/resource stay out —
    // a timestamp would break the pure serializer; resource is N/A for an internal
    // concept). okf-check still only REQUIRES type; these clear its warnings.
    for (const sub of ["brain/profile.md", "brain/operations.md"]) {
      const block = readFileSync(join(root, sub), "utf8").match(/^---\n([\s\S]*?)\n---\n/);
      assert.ok(block, `${sub} has a frontmatter block`);
      assert.match(block![1], /^title:\s*\S/m, `${sub} has a title`);
      assert.match(block![1], /^description:\s*\S/m, `${sub} has a description`);
    }
  });

  test("each directory level under brain/ has its own index.md (progressive disclosure)", () => {
    assert.ok(existsSync(join(root, "brain/index.md")), "brain/index.md");
    assert.ok(existsSync(join(root, "brain/journal/index.md")), "brain/journal/index.md");
  });
});
