import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { http, HttpResponse } from 'msw';

import { httpRequest, setupHttp } from '@/api/http-init';

import { CSRF_TOKEN } from './msw/handlers';
import { server } from './msw/server';

const ORIGIN = 'http://localhost';

describe('httpRequest against the MSW-mocked network', () => {
  beforeEach(() => {
    vi.stubGlobal('document', { querySelector: () => null });
    window.X_UI_BASE_PATH = ORIGIN;
    setupHttp();
  });

  afterEach(() => {
    vi.unstubAllGlobals();
    delete window.X_UI_BASE_PATH;
  });

  it('fetches a CSRF token, then refetches and retries once after a 403', async () => {
    let posts = 0;
    const sentTokens: (string | null)[] = [];
    server.use(
      http.get(`${ORIGIN}/csrf-token`, () => HttpResponse.json({ success: true, obj: CSRF_TOKEN })),
      http.post(`${ORIGIN}/panel/api/test`, ({ request }) => {
        posts += 1;
        sentTokens.push(request.headers.get('X-CSRF-Token'));
        if (posts === 1) return new HttpResponse(null, { status: 403 });
        return HttpResponse.json({ success: true, obj: 'saved' });
      }),
    );

    const res = await httpRequest('POST', '/panel/api/test', { hello: 'world' });

    expect(posts).toBe(2);
    expect(sentTokens).toEqual([CSRF_TOKEN, CSRF_TOKEN]);
    expect(res.status).toBe(200);
    expect(res.data).toEqual({ success: true, obj: 'saved' });
  });

  it('on a 403 refetches a fresh token from the server even when a stale meta tag is present', async () => {
    const STALE = 'stale-meta-token';
    const FRESH = 'fresh-server-token';
    vi.stubGlobal('document', {
      querySelector: (selector: string) =>
        selector === 'meta[name="csrf-token"]' ? { getAttribute: () => STALE } : null,
    });
    setupHttp();

    let posts = 0;
    const sentTokens: (string | null)[] = [];
    server.use(
      http.get(`${ORIGIN}/csrf-token`, () => HttpResponse.json({ success: true, obj: FRESH })),
      http.post(`${ORIGIN}/panel/api/test`, ({ request }) => {
        posts += 1;
        const token = request.headers.get('X-CSRF-Token');
        sentTokens.push(token);
        if (token !== FRESH) return new HttpResponse(null, { status: 403 });
        return HttpResponse.json({ success: true, obj: 'saved' });
      }),
    );

    const res = await httpRequest('POST', '/panel/api/test', { hello: 'world' });

    expect(sentTokens).toEqual([STALE, FRESH]);
    expect(posts).toBe(2);
    expect(res.status).toBe(200);
  });

  it('resolves a safe GET without requesting a CSRF token', async () => {
    let csrfHits = 0;
    server.use(
      http.get(`${ORIGIN}/csrf-token`, () => {
        csrfHits += 1;
        return HttpResponse.json({ success: true, obj: CSRF_TOKEN });
      }),
      http.get(`${ORIGIN}/panel/api/status`, () =>
        HttpResponse.json({ success: true, obj: { up: true } }),
      ),
    );

    const res = await httpRequest('GET', '/panel/api/status');

    expect(csrfHits).toBe(0);
    expect(res.status).toBe(200);
    expect(res.data).toEqual({ success: true, obj: { up: true } });
  });
});
