import { Effect } from "effect";
import { FetchError, ResponseTextError } from "../../../utils/http";
import { BrandValidationError, SVGString } from "../../../utils/validation/svg";
import { clearIconCache, emptyDefaultSvg, fetchIconSvg } from "../icons";
describe('icon utils:', () => {
    beforeAll(() => {
        global.DOMParser = class {
            parseFromString(str, type) {
                return {
                    documentElement: {
                        nodeName: str.includes('<svg') ? 'svg' : 'not-svg',
                    },
                };
            }
        };
    });
    beforeEach(() => {
        jest.resetAllMocks();
        global.fetch = jest.fn();
        return Effect.runPromise(clearIconCache());
    });
    const validSvg = '<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg>';
    const invalidSvg = '<div>not an svg</div>';
    const iconName = 'actions';
    function mockFetchSuccess(svg = validSvg) {
        global.fetch.mockResolvedValueOnce({
            text: () => Promise.resolve(svg),
        });
    }
    function mockFetchFailure() {
        global.fetch.mockRejectedValueOnce(new Error('fail'));
    }
    test('fetchIcon returns valid SVGString when fetch succeeds with valid SVG', async () => {
        mockFetchSuccess(validSvg);
        const result = await Effect.runPromise(fetchIconSvg(iconName));
        expect(result).toContain('<svg');
        expect(result).not.toBe(emptyDefaultSvg());
    });
    test('fetchIcon throws a specific FetchError when fetch fails', async () => {
        mockFetchFailure();
        const res = await Effect.runPromise(fetchIconSvg(iconName).pipe(Effect.flip));
        expect(res).toBeInstanceOf(FetchError);
    });
    test('fetchIcon throws a specific InvalidSvgError when SVG is invalid', async () => {
        mockFetchSuccess(invalidSvg);
        const result = await Effect.runPromise(fetchIconSvg(iconName).pipe(Effect.flip));
        expect(result).toBeInstanceOf(BrandValidationError);
        expect(result.message).toContain('SVGString');
    });
    test('fetchIcon throws specific NotFoundError when icon is missing', async () => {
        global.fetch.mockResolvedValueOnce({
            text: () => Promise.reject(new Error('not found')),
        });
        const result = await Effect.runPromise(fetchIconSvg('missing').pipe(Effect.flip));
        expect(result).toBeInstanceOf(ResponseTextError);
    });
    test('fetchIcon throws specific BrandValidationError for empty SVG string', async () => {
        mockFetchSuccess('');
        const result = await Effect.runPromise(fetchIconSvg(iconName).pipe(Effect.flip));
        expect(result).toBeInstanceOf(BrandValidationError);
    });
    test('fetchIcon throws specific BrandValidationError for non-string SVG', async () => {
        mockFetchSuccess(123);
        const result = await Effect.runPromise(fetchIconSvg(iconName).pipe(Effect.flip));
        expect(result).toBeInstanceOf(BrandValidationError);
    });
    test('SVGString branding enforces valid SVG', () => {
        expect(() => SVGString(validSvg)).not.toThrow();
        expect(() => SVGString(invalidSvg)).toThrow();
        expect(() => SVGString('')).toThrow();
        expect(() => SVGString(123)).toThrow();
    });
    test('emptyDefaultSvg is a valid branded SVGString', () => {
        expect(() => SVGString(emptyDefaultSvg())).not.toThrow();
        expect(emptyDefaultSvg()).toContain('<svg');
    });
    test('fetchIcon uses default weight if not provided', async () => {
        mockFetchSuccess(validSvg);
        const result = await Effect.runPromise(fetchIconSvg(iconName));
        expect(result).toContain('<svg');
    });
    test('fetchIcon handles multiple calls and caches result', async () => {
        mockFetchSuccess(validSvg);
        const result1 = await Effect.runPromise(fetchIconSvg(iconName));
        const result2 = await Effect.runPromise(fetchIconSvg(iconName));
        expect(result1).toContain('<svg');
        expect(result2).toBe(result1);
    });
});
