import { describe, test, afterEach } from 'node:test';
import assert from 'node:assert/strict';
import { join } from 'node:path';
import { homedir } from 'node:os';
import { getDataRoot, getStateFile } from '../data-root.mjs';

// Resolver contract for the per-user data dir (M0). The resolver reads env at
// CALL time (not module load) so these env stubs take effect; restore in
// afterEach. Pattern: scripts/analytics/tests/storage-root.test.ts:14-26.
describe('data-root resolver', () => {
  const saved = {
    HOME: process.env.HOME,
    USERPROFILE: process.env.USERPROFILE,
    LINKEDIN_STUDIO_DATA: process.env.LINKEDIN_STUDIO_DATA,
    STATE_FILE: process.env.STATE_FILE,
  };

  afterEach(() => {
    for (const [k, v] of Object.entries(saved)) {
      if (v === undefined) delete process.env[k];
      else process.env[k] = v;
    }
  });

  describe('getDataRoot', () => {
    test('default subdir form: getDataRoot("analytics") = HOME/.claude/linkedin-studio/analytics', () => {
      process.env.HOME = '/home/tester';
      delete process.env.USERPROFILE;
      delete process.env.LINKEDIN_STUDIO_DATA;

      assert.equal(
        getDataRoot('analytics'),
        join('/home/tester', '.claude', 'linkedin-studio', 'analytics'),
      );
    });

    test('no-arg form returns the root itself (M5 — needed by the REMEMBER write)', () => {
      process.env.HOME = '/home/tester';
      delete process.env.USERPROFILE;
      delete process.env.LINKEDIN_STUDIO_DATA;

      assert.equal(getDataRoot(), join('/home/tester', '.claude', 'linkedin-studio'));
    });

    test('LINKEDIN_STUDIO_DATA override wins (subdir and root forms)', () => {
      process.env.HOME = '/home/tester';
      process.env.LINKEDIN_STUDIO_DATA = '/tmp/lis-data';

      assert.equal(getDataRoot('analytics'), join('/tmp/lis-data', 'analytics'));
      assert.equal(getDataRoot(), '/tmp/lis-data');
    });

    test('empty HOME + USERPROFILE falls back to os.homedir(), never "" (no relative-path trap)', () => {
      delete process.env.HOME;
      delete process.env.USERPROFILE;
      delete process.env.LINKEDIN_STUDIO_DATA;

      const root = getDataRoot('analytics');
      assert.equal(root, join(homedir(), '.claude', 'linkedin-studio', 'analytics'));
      assert.ok(!root.startsWith('.claude'), `root must be absolute, got relative: ${root}`);
    });
  });

  describe('getStateFile', () => {
    test('default = HOME/.claude/linkedin-studio.local.md (mirrors state-updater.mjs:12)', () => {
      process.env.HOME = '/home/tester';
      delete process.env.USERPROFILE;
      delete process.env.STATE_FILE;

      assert.equal(getStateFile(), join('/home/tester', '.claude', 'linkedin-studio.local.md'));
    });

    test('STATE_FILE override wins', () => {
      process.env.HOME = '/home/tester';
      process.env.STATE_FILE = '/tmp/custom-state.md';

      assert.equal(getStateFile(), '/tmp/custom-state.md');
    });
  });
});

// Twin consistency with scripts/analytics/src/utils/storage.ts:getDataRoot.
// The TS twin cannot be imported into this no-tsx .mjs run, so we assert this
// .mjs resolver against the SAME contract literals that storage-root.test.ts
// asserts for the TS twin (the behavioral-consistency model — a header-only
// "bit-identical" claim is not a test). Change one twin → update this block and
// its TS mirror in lockstep. R2's mitigation.
describe('twin consistency (storage.ts:getDataRoot)', () => {
  const saved = {
    HOME: process.env.HOME,
    USERPROFILE: process.env.USERPROFILE,
    LINKEDIN_STUDIO_DATA: process.env.LINKEDIN_STUDIO_DATA,
  };

  afterEach(() => {
    for (const [k, v] of Object.entries(saved)) {
      if (v === undefined) delete process.env[k];
      else process.env[k] = v;
    }
  });

  // These literals are the shared contract — storage-root.test.ts asserts the
  // identical strings for the TS twin; keep them character-for-character in sync.
  test('default matches the TS twin contract literal (HOME-stubbed)', () => {
    process.env.HOME = '/home/tester';
    delete process.env.USERPROFILE;
    delete process.env.LINKEDIN_STUDIO_DATA;

    assert.equal(
      getDataRoot('analytics'),
      join('/home/tester', '.claude', 'linkedin-studio', 'analytics'),
    );
  });

  test('LINKEDIN_STUDIO_DATA override matches the TS twin contract literal', () => {
    process.env.LINKEDIN_STUDIO_DATA = '/tmp/lis-data';

    assert.equal(getDataRoot('analytics'), join('/tmp/lis-data', 'analytics'));
  });
});
