import { describe, it, expect, vi, beforeAll, beforeEach } from 'vitest';
import { postJson } from '../src/index.js';
import { saveEnv, resetEnv, stubEnv, createMockFetch } from './helpers.js';
import { setOpencodeClient } from '../src/index.js';

beforeAll(() => saveEnv());

describe('TestPostJson', () => {
  beforeEach(() => {
    resetEnv();
    setOpencodeClient(null);
    vi.restoreAllMocks();
  });

  it('returns parsed JSON on success', async () => {
    stubEnv({ OG_AUTH_API_KEY: 'test-key' });
    vi.stubGlobal('fetch', createMockFetch({
      ok: true, status: 200,
      json: () => Promise.resolve({ ok: true }),
    }));

    const result = await postJson('http://localhost:8090/api/v1/test', { data: 1 }, 8000);
    expect(result).toEqual({ ok: true });
  });

  it('returns null on non-OK HTTP response', async () => {
    vi.stubGlobal('fetch', createMockFetch({
      ok: false, status: 500,
      json: () => Promise.resolve({}),
    }));

    const result = await postJson('http://localhost:8090/api/v1/test', {}, 8000);
    expect(result).toBeNull();
  });

  it('returns null on fetch error (network failure)', async () => {
    vi.stubGlobal('fetch', vi.fn().mockRejectedValue(new Error('ECONNREFUSED')));

    const result = await postJson('http://localhost:8090/api/v1/test', {}, 8000);
    expect(result).toBeNull();
  });

  it('returns null on timeout (AbortError)', async () => {
    vi.stubGlobal('fetch', vi.fn().mockRejectedValue(
      new DOMException('The operation was aborted', 'AbortError'),
    ));

    const result = await postJson('http://localhost:8090/api/v1/test', {}, 8000);
    expect(result).toBeNull();
  });

  it('sends correct headers including auth when key is set', async () => {
    stubEnv({
      OG_AUTH_API_KEY: 'my-key',
      OG_ACCOUNT_ID: 'acct-1',
      OG_USER_ID: 'u-1',
    });
    const mockFetch = vi.fn().mockResolvedValue({
      ok: true, status: 200,
      json: () => Promise.resolve({}),
    });
    vi.stubGlobal('fetch', mockFetch);

    await postJson('http://localhost:8090/test', {}, 8000);
    const opts = mockFetch.mock.calls[0]![1] as Record<string, unknown>;
    const headers = opts.headers as Record<string, string>;
    expect(headers['X-API-Key']).toBe('my-key');
    expect(headers['X-Account-ID']).toBe('acct-1');
    expect(headers['Content-Type']).toBe('application/json');
  });
});