import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { parseHTML } from 'linkedom';

type UsageModule = {
  UsagePage: {
    render: (el: unknown, client: unknown) => Promise<void>;
    teardown: () => void;
  };
};

function createClient() {
  const calls: Array<{ method: string; params?: Record<string, unknown> }> = [];
  const client = {
    async call(method: string, params?: Record<string, unknown>) {
      calls.push({ method, params });
      if (method === 'system.tokenUsage') {
        return {
          sessions: [
            {
              sessionId: 'ws:alpha',
              total: { inputTokens: 100, outputTokens: 50, calls: 3, estimatedCost: 0.02 },
              delegation: { fast: { inputTokens: 80, outputTokens: 40 } },
            },
          ],
        };
      }
      if (method === 'system.contextUsage') {
        return {
          sessions: [
            { sessionId: 'ws:alpha', budget: { usagePct: 40.5, estimatedTokens: 150, contextWindow: 1000 } },
          ],
        };
      }
      return null;
    },
  };
  return { client, calls };
}

describe('UsagePage wiring', () => {
  let root: any;
  let windowObj: any;
  let UsagePage: UsageModule['UsagePage'];

  beforeEach(async () => {
    vi.resetModules();
    const { document, window } = parseHTML('<!doctype html><html><body><div id="root"></div></body></html>') as unknown as {
      document: any;
      window: any;
    };
    (globalThis as any).document = document;
    (globalThis as any).window = window;
    root = document.getElementById('root');
    windowObj = window;

    // @ts-expect-error JS module without declaration file.
    const mod = await import('./usage.js') as unknown as UsageModule;
    UsagePage = mod.UsagePage;
  });

  afterEach(() => {
    UsagePage.teardown();
    vi.useRealTimers();
    delete (globalThis as any).document;
    delete (globalThis as any).window;
  });

  it('wires refresh button and auto-refresh timer', async () => {
    vi.useFakeTimers();
    const { client, calls } = createClient();

    await UsagePage.render(root, client);

    expect(calls.filter((entry) => entry.method === 'system.tokenUsage').length).toBe(1);
    expect(calls.filter((entry) => entry.method === 'system.contextUsage').length).toBe(1);

    root.querySelector('#usage-refresh-btn').dispatchEvent(new windowObj.Event('click', { bubbles: true }));
    await Promise.resolve();

    expect(calls.filter((entry) => entry.method === 'system.tokenUsage').length).toBe(2);
    expect(calls.filter((entry) => entry.method === 'system.contextUsage').length).toBe(2);

    await vi.advanceTimersByTimeAsync(30000);
    await Promise.resolve();

    expect(calls.filter((entry) => entry.method === 'system.tokenUsage').length).toBe(3);
    expect(calls.filter((entry) => entry.method === 'system.contextUsage').length).toBe(3);

    UsagePage.teardown();
    await vi.advanceTimersByTimeAsync(60000);

    expect(calls.filter((entry) => entry.method === 'system.tokenUsage').length).toBe(3);
  });
});
