import { resolveNetaclawTraySecret, fixedTimeCompare } from '../../../../src/modules/netaclaw/runtime/tray_secret.js';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';

describe('resolveNetaclawTraySecret', () => {
  let tmpDir: string;
  beforeEach(() => {
    tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'neta-secret-'));
  });
  afterEach(() => {
    delete process.env.NETA_TRAY_SECRET;
    try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch {}
  });

  it('returns env value when set', () => {
    process.env.NETA_TRAY_SECRET = 'env-sec';
    expect(resolveNetaclawTraySecret(tmpDir)).toBe('env-sec');
  });

  it('falls back to tray-info.json', () => {
    fs.mkdirSync(path.join(tmpDir, 'runtime'), { recursive: true });
    fs.writeFileSync(
      path.join(tmpDir, 'runtime', 'tray-info.json'),
      JSON.stringify({ traySecret: 'file-sec', controlBaseUrl: 'http://x' }),
    );
    expect(resolveNetaclawTraySecret(tmpDir)).toBe('file-sec');
  });

  it('returns null when neither source is available', () => {
    expect(resolveNetaclawTraySecret(tmpDir)).toBeNull();
  });

  it('env wins over file', () => {
    process.env.NETA_TRAY_SECRET = 'env-sec';
    fs.mkdirSync(path.join(tmpDir, 'runtime'), { recursive: true });
    fs.writeFileSync(
      path.join(tmpDir, 'runtime', 'tray-info.json'),
      JSON.stringify({ traySecret: 'file-sec' }),
    );
    expect(resolveNetaclawTraySecret(tmpDir)).toBe('env-sec');
  });

  it('ignores empty traySecret in file', () => {
    fs.mkdirSync(path.join(tmpDir, 'runtime'), { recursive: true });
    fs.writeFileSync(
      path.join(tmpDir, 'runtime', 'tray-info.json'),
      JSON.stringify({ traySecret: '' }),
    );
    expect(resolveNetaclawTraySecret(tmpDir)).toBeNull();
  });
});

describe('fixedTimeCompare', () => {
  it('returns true for equal strings', () => {
    expect(fixedTimeCompare('abc', 'abc')).toBe(true);
  });
  it('returns false for different strings of equal length', () => {
    expect(fixedTimeCompare('abc', 'abd')).toBe(false);
  });
  it('returns false for different lengths without short-circuit', () => {
    expect(fixedTimeCompare('a', 'abc')).toBe(false);
    expect(fixedTimeCompare('abc', 'a')).toBe(false);
  });
  it('returns false for null/undefined inputs', () => {
    expect(fixedTimeCompare('a', '')).toBe(false);
    expect(fixedTimeCompare('', 'a')).toBe(false);
    expect(fixedTimeCompare('', '')).toBe(true);
  });
});
