import { describe, expect, it, beforeAll, afterAll } from 'vitest';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { Substrate } from '../src/core/substrate';

let dir: string;

beforeAll(() => {
  dir = fs.mkdtempSync(path.join(os.tmpdir(), 'rha-substrate-'));
});

afterAll(() => {
  fs.rmSync(dir, { recursive: true, force: true });
});

describe('supergit substrate', () => {
  it('initializes a git repo with a genesis ledger node', () => {
    const s = Substrate.init(dir);
    const rows = s.allRows();
    expect(rows).toHaveLength(1);
    expect(rows[0].type).toBe('genesis');
    expect(fs.existsSync(path.join(dir, '.git'))).toBe(true);
    expect(fs.existsSync(path.join(dir, '.supergit', 'ledger.csv'))).toBe(true);
  });

  it('appends typed nodes with monotonically increasing steps', () => {
    const s = Substrate.open(dir);
    const a = s.recordNode({ type: 'decision', summary: 'first, with "quotes", and commas' });
    const b = s.recordNode({ type: 'error', featureId: 'F1', bugClass: 'todo-stub', status: 'open', causeId: a, summary: 'boom' });
    const rows = s.allRows();
    expect(rows[rows.length - 1].id).toBe(b);
    expect(rows[rows.length - 1].causeId).toBe(a);
    expect(rows[rows.length - 2].step).toBeLessThan(rows[rows.length - 1].step);
  });

  it('round-trips the ledger through CSV including escapes', () => {
    const reopened = Substrate.open(dir);
    const rows = reopened.allRows();
    const withQuotes = rows.find(r => r.summary.includes('"quotes"'));
    expect(withQuotes).toBeDefined();
    expect(withQuotes!.summary).toBe('first, with "quotes", and commas');
  });

  it('records forward dependency pointers as append-only edge rows', () => {
    const s = Substrate.open(dir);
    const from = s.recordNode({ type: 'spec', featureId: 'F1', summary: 'codec' });
    const to = s.recordNode({ type: 'spec', featureId: 'F3', summary: 'service' });
    s.recordEdge(from, to);
    expect(s.downstream(from)).toContain(to);
  });

  it('synchronizes ledger nodes with git commits via trailers', () => {
    const s = Substrate.open(dir);
    const node = s.recordNode({ type: 'code', featureId: 'F1', summary: 'impl' });
    fs.writeFileSync(path.join(dir, 'hello.txt'), 'hi');
    const sha = s.commit(node, 'feat(F1): hello');
    expect(sha).toMatch(/^[0-9a-f]{40}$/);
    expect(s.commitForNode(node)).toBe(sha);
    const msg = s.git(['log', '-1', '--format=%B']);
    expect(msg).toContain(`Supergit-Node: ${node}`);
    expect(msg).toContain('Supergit-Type: code');
  });

  it('walks causal lineage backward', () => {
    const s = Substrate.open(dir);
    const a = s.recordNode({ type: 'test', featureId: 'F2', summary: 'ir suite' });
    const b = s.recordNode({ type: 'code', featureId: 'F2', causeId: a, summary: 'impl' });
    const c = s.recordNode({ type: 'error', featureId: 'F2', causeId: b, bugClass: 'test-failure', summary: 'red' });
    const lineage = s.lineage(c);
    expect(lineage[0]).toContain(c);
    expect(lineage[1]).toContain(b);
    expect(lineage[2]).toContain(a);
  });
});
