/**
 * Tests for security/safe-fetch.js
 *
 * Tests the safeFetch wrapper that validates URLs before making
 * fetch requests, blocking unsafe external URLs.
 */

// Load url-validator first (safe-fetch depends on it)
import '@js/security/url-validator.js';
import '@js/security/safe-fetch.js';

describe('safeFetch', () => {
    const originalFetch = globalThis.fetch;

    beforeEach(() => {
        globalThis.fetch = vi.fn(() =>
            Promise.resolve(new Response('ok', { status: 200 }))
        );
    });

    afterEach(() => {
        globalThis.fetch = originalFetch;
    });

    it('allows internal URLs starting with /', async () => {
        await window.safeFetch('/api/research/1');
        expect(globalThis.fetch).toHaveBeenCalledWith('/api/research/1', {});
    });

    it('allows internal URLs with custom options', async () => {
        const opts = { method: 'POST', body: '{}' };
        await window.safeFetch('/api/start', opts);
        expect(globalThis.fetch).toHaveBeenCalledWith('/api/start', opts);
    });

    it('allows safe external URLs (https)', async () => {
        await window.safeFetch('https://example.com/api');
        expect(globalThis.fetch).toHaveBeenCalled();
    });

    it('allows safe external URLs (http)', async () => {
        await window.safeFetch('http://example.com/api');
        expect(globalThis.fetch).toHaveBeenCalled();
    });

    it('blocks javascript: URLs', async () => {
        await expect(window.safeFetch('javascript:alert(1)'))
            .rejects.toThrow('Blocked unsafe URL');
    });

    it('blocks data: URLs', async () => {
        await expect(window.safeFetch('data:text/html,<h1>xss</h1>'))
            .rejects.toThrow('Blocked unsafe URL');
    });

    it('blocks vbscript: URLs', async () => {
        await expect(window.safeFetch('vbscript:msgbox'))
            .rejects.toThrow('Blocked unsafe URL');
    });

    it('does not call fetch for blocked URLs', async () => {
        try {
            await window.safeFetch('javascript:void(0)');
        } catch {}
        expect(globalThis.fetch).not.toHaveBeenCalled();
    });
});
