import { describe, expect, it, jest } from '@jest/globals';
import { UrlFactory, ControllerUrlFactory } from '../js/medium/urlfactory.js';

const Factories = [
    { title: 'UrlFactory' , type: 'room', factory: UrlFactory },
    { title: 'ControllerUrlFactory', type: 'controller', factory: ControllerUrlFactory },
];

const Protocols = [
    { http: 'http',  ws: 'ws',  base: 'test.com/path',  normalized: 'test.com/path' },
    { http: 'http',  ws: 'ws',  base: 'test.com/path/', normalized: 'test.com/path' },
    { http: 'https', ws: 'wss', base: 'test.com/path',  normalized: 'test.com/path' },
    { http: 'https', ws: 'wss', base: 'test.com/path/', normalized: 'test.com/path' }
];

describe.each(Factories)('$title(baseUrl, group, channels)', ({ factory, type }) => {

    it('constructor throws if group is empty or not a string', () => {
        const base = 'https://localhost/path';
        ['', null, ['group']].forEach(badGroup => {
            expect(() => new factory(base, badGroup)).toThrowError(TypeError);
        });
    })

    it('.restEndpoint(path) returns {baseUrl}/rest/{path}', () => {
        const restPath = 'token/list';
        const expectedSlug = 'rest/token/list';
        Protocols.forEach(({ http, base, normalized }) => {
            const baseUrl = `${http}://${base}`;
            const expectedPath = `${http}://${normalized}/${expectedSlug}`;
            const urlFactory = new factory(baseUrl, 'group');
            expect(urlFactory.restEndpoint(restPath)).toEqual(expectedPath);
        });
    })

    it('.publisherEndpoint(channels) returns {baseUrl}/{group}/pub/{channels}', () => {
        const group = 'grp';
        const channels = ['ch1', 'ch7'];
        const expectedSlug = 'grp/pub/ch1,ch7';
        Protocols.forEach(({ http, base, normalized }) => {
            const baseUrl = `${http}://${base}`;
            const expectedPath = `${http}://${normalized}/${expectedSlug}`;
            const urlFactory = new factory(baseUrl, group);
            expect(urlFactory.publisherEndpoint(channels)).toEqual(expectedPath);
        });
    })

    it('.publisherEndpoint() throws TypeError for bad or empty "channels" parameter', () => {
        const urlFactory = new factory('https://test.com/', 'group');

        ['', null, {}, {a:42}].forEach(badChannel => {
            expect(() => urlFactory.publisherEndpoint(badChannel)).toThrowError(TypeError);
        });
    })

    const msgEndpoint = type === 'room'
        ? '{baseUrl}/{group}/room/pub{pub}/sub{sub}/{token}'
        : '{baseUrl}/{group}/controller/sub{sub}/{token}';

    it(`.messengerEndpoint(token) returns ${msgEndpoint} with ws/wss protocol for http/https`, () => {
        const token = 'accesstoken';
        const group = 'grp';
        const channels = { pub: 'ch1,ch2', sub: ['ch3','ch4'] };
        const expectedSlug = type === 'room'
            ? 'grp/room/pubch1,ch2/subch3,ch4/'
            : 'grp/controller/subch3,ch4/';
        Protocols.forEach(({ http, ws, base, normalized }) => {
            const baseUrl = `${http}://${base}`;
            const expectedPath = `${ws}://${normalized}/${expectedSlug}`;
            const urlFactory = new factory(baseUrl, group, channels);
            expect(urlFactory.messengerEndpoint()).toEqual(expectedPath);
            expect(urlFactory.messengerEndpoint(token)).toEqual(expectedPath + token);
        });
    })

});
