import { SuiteLogger } from '@theorchard/suite-utils';
import { themeAwal } from '../themes/themeAwal';
import { applyTheme, parseRgbString, rgbToHex } from '../utils';

const RED_RGB_1 = 'rgb(255, 0, 0)';
const RED_RGB_2 = 'rgb(255,0,0)';
const RED_RGB_3 = 'rgb(255 0 0)';

const SuiteLoggerErrorSpy = jest.spyOn(SuiteLogger, 'error');

afterEach(() => {
    jest.clearAllMocks();
});

describe('applyTheme', () => {
    let linkElement: HTMLLinkElement;
    const originalFaviconUrl = 'https://test.com/orchard/favicon.png';

    beforeAll(() => {
        linkElement = document.createElement('link');
        linkElement.rel = 'icon';
        document.head.append(linkElement);
    });

    beforeEach(() => {
        linkElement.href = originalFaviconUrl;
    });

    test('updates :root css variables', () => {
        applyTheme('awal');

        const rootElement = document.querySelector<HTMLElement>(':root')!;

        Object.entries(themeAwal.colors).forEach(([name, value]) => {
            expect(rootElement.style.getPropertyValue(`--${name}`)).toEqual(value);
        });
    });

    test('updates css variables when switching themes', () => {
        applyTheme('awal');

        const rootElement = document.querySelector<HTMLElement>(':root')!;
        const awalIconColor = rootElement.style.getPropertyValue('--app-icon-gradient-color-0');

        expect(awalIconColor).toEqual(themeAwal.colors['app-icon-gradient-color-0']);

        applyTheme('orchard');

        const orchardIconColor = rootElement.style.getPropertyValue('--app-icon-gradient-color-0');

        expect(orchardIconColor).not.toEqual(awalIconColor);
        expect(rootElement.style.length).toBeGreaterThan(0);
    });
});

describe('parseRgbString', () => {
    test('parses rgb string in all working formats', () => {
        expect(parseRgbString(RED_RGB_1)).toEqual({ r: 255, g: 0, b: 0 });
        expect(parseRgbString(RED_RGB_2)).toEqual({ r: 255, g: 0, b: 0 });
        expect(parseRgbString(RED_RGB_3)).toEqual({ r: 255, g: 0, b: 0 });
        // Also checking for extra-padded format (rare, but "valid")
        expect(parseRgbString('rgb(255,  0,  0)')).toEqual({ r: 255, g: 0, b: 0 });
    });

    test('returns black when invalid format', () => {
        const notRGB = 'hsl(50 80% 40%)';
        expect(parseRgbString(notRGB)).toEqual({ r: 0, g: 0, b: 0 });
        expect(SuiteLoggerErrorSpy).toHaveBeenCalledWith(
            'parseRgbString',
            'Invalid RGB string format'
        );
    });
});

describe('rgbToHex', () => {
    test('converts rgb string to hex', () => {
        expect(rgbToHex(RED_RGB_1)).toEqual('#ff0000');
        expect(rgbToHex(RED_RGB_2)).toEqual('#ff0000');
        expect(rgbToHex(RED_RGB_3)).toEqual('#ff0000');
    });

    test('returns the same string when its not a valid rgb', () => {
        const notValidRgb = 'rgb(255, 0, 300)';
        expect(rgbToHex(notValidRgb)).toEqual(notValidRgb);
        expect(SuiteLoggerErrorSpy).toHaveBeenCalledWith(
            'rgbToHex',
            'RGB values must be between 0 and 255'
        );
    });

    test('returns the same hex value when its valid', () => {
        const alreadyHex = '#ff0000';
        expect(rgbToHex(alreadyHex)).toEqual(alreadyHex);
    });

    test('returns black if its not a valid hex', () => {
        const notValidHex = '#ff000';
        expect(rgbToHex(notValidHex)).toEqual('#000000');
        expect(SuiteLoggerErrorSpy).toHaveBeenCalledWith(
            'parseRgbString',
            'Invalid RGB string format'
        );
    });
});
