import { describe, expect, it, beforeEach, afterEach } from 'vitest';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import {
  injectStaleBanner,
  newestMtime,
  STALE_BUNDLE_MSG,
  webBundleFreshness,
} from '../src/server/webBundle';

describe('webBundle freshness', () => {
  let root: string;

  beforeEach(() => {
    root = fs.mkdtempSync(path.join(os.tmpdir(), 'rha-web-bundle-'));
    fs.mkdirSync(path.join(root, 'web', 'src'), { recursive: true });
  });

  afterEach(() => {
    fs.rmSync(root, { recursive: true, force: true });
  });

  it('newestMtime returns null for missing dir', () => {
    expect(newestMtime(path.join(root, 'nope'))).toBeNull();
  });

  it('marks stale when dist is missing', () => {
    fs.writeFileSync(path.join(root, 'web', 'src', 'App.tsx'), 'x');
    const f = webBundleFreshness(root);
    expect(f.stale).toBe(true);
    expect(f.distMtime).toBeNull();
    expect(f.srcMtime).toBeGreaterThan(0);
  });

  it('marks stale when dist is older than src', () => {
    const src = path.join(root, 'web', 'src', 'App.tsx');
    const distDir = path.join(root, 'web', 'dist');
    fs.mkdirSync(distDir, { recursive: true });
    const distFile = path.join(distDir, 'index.html');
    fs.writeFileSync(distFile, '<html></html>');
    const old = Date.now() - 60_000;
    fs.utimesSync(distFile, new Date(old), new Date(old));
    fs.writeFileSync(src, 'newer');
    const now = Date.now();
    fs.utimesSync(src, new Date(now), new Date(now));
    expect(webBundleFreshness(root).stale).toBe(true);
  });

  it('is fresh when dist is newer than src', () => {
    const src = path.join(root, 'web', 'src', 'App.tsx');
    const distDir = path.join(root, 'web', 'dist');
    fs.mkdirSync(distDir, { recursive: true });
    fs.writeFileSync(src, 'old');
    const old = Date.now() - 60_000;
    fs.utimesSync(src, new Date(old), new Date(old));
    const distFile = path.join(distDir, 'index.html');
    fs.writeFileSync(distFile, '<html></html>');
    const now = Date.now();
    fs.utimesSync(distFile, new Date(now), new Date(now));
    expect(webBundleFreshness(root).stale).toBe(false);
  });

  it('injectStaleBanner inserts once and mentions build:web', () => {
    const html = '<!doctype html><html><body><div id="root"></div></body></html>';
    const once = injectStaleBanner(html);
    expect(once).toContain('rha-stale-bundle-banner');
    expect(once).toContain(STALE_BUNDLE_MSG);
    expect(injectStaleBanner(once)).toBe(once);
  });
});
