import assert from 'node:assert/strict';

import {
    addWindowIdToTurboHeaders,
    isSameOriginRequest,
    withWindowIdFetchInit,
} from '../../assets/js/windowIdRequest.js';

const currentHref = 'https://www.example.com/la-maison';
const windowId = 'window-123';

for (const input of [
    '/api/cart',
    'https://www.example.com/api/cart',
    new URL('https://www.example.com/api/cart'),
    new Request('https://www.example.com/api/cart'),
]) {
    assert.equal(
        isSameOriginRequest(input, currentHref),
        true,
        `${String(input)} doit être reconnu comme une requête de même origine.`,
    );
}

const crossRealmExternalRequest = {
    url: 'https://data.geopf.fr/tms/1.0.0/PLAN.IGN/0/0/0.pbf',
    headers: new Headers({Accept: 'application/x-protobuf'}),
    [Symbol.toStringTag]: 'Request',
};

assert.equal(
    isSameOriginRequest(crossRealmExternalRequest, currentHref),
    false,
    'Un Request externe provenant d’une autre fenêtre ne doit pas être pris pour une URL relative.',
);

for (const input of [
    'https://data.geopf.fr/tms/1.0.0/PLAN.IGN/metadata.json',
    'https://www.example.com.evil.test/api/cart',
    'https://www.example.com:8443/api/cart',
    new URL('https://data.geopf.fr/tms/1.0.0/PLAN.IGN/metadata.json'),
    new Request('https://data.geopf.fr/tms/1.0.0/PLAN.IGN/metadata.json'),
]) {
    assert.equal(
        isSameOriginRequest(input, currentHref),
        false,
        `${String(input)} ne doit pas être reconnu comme une requête de même origine.`,
    );
}

const sameOriginInit = {
    headers: {
        Accept: 'application/json',
    },
};
const sameOriginResult = withWindowIdFetchInit(
    '/api/cart',
    sameOriginInit,
    windowId,
    currentHref,
);

assert.notEqual(
    sameOriginResult,
    sameOriginInit,
    'Les options fetch de même origine doivent être copiées avant modification.',
);
assert.equal(sameOriginResult.headers.get('Accept'), 'application/json');
assert.equal(sameOriginResult.headers.get('X-Window-Id'), windowId);
assert.equal(
    new Headers(sameOriginInit.headers).has('X-Window-Id'),
    false,
    'Les options fetch d’origine ne doivent pas être mutées.',
);

const nullInitResult = withWindowIdFetchInit(
    '/api/cart',
    null,
    windowId,
    currentHref,
);

assert.equal(
    nullInitResult.headers.get('X-Window-Id'),
    windowId,
    'fetch(url, null) doit rester compatible avec l’ajout de X-Window-Id.',
);

const urlInputResult = withWindowIdFetchInit(
    new URL('/api/cart', currentHref),
    {},
    windowId,
    currentHref,
);

assert.equal(urlInputResult.headers.get('X-Window-Id'), windowId);

const sameOriginRequest = new Request(
    'https://www.example.com/api/cart',
    {
        headers: {
            Accept: 'application/problem+json',
        },
    },
);
const requestResult = withWindowIdFetchInit(
    sameOriginRequest,
    {},
    windowId,
    currentHref,
);

assert.equal(requestResult.headers.get('Accept'), 'application/problem+json');
assert.equal(requestResult.headers.get('X-Window-Id'), windowId);
assert.equal(
    sameOriginRequest.headers.has('X-Window-Id'),
    false,
    'Le Request transmis à fetch ne doit pas être muté.',
);

const requestInitHeadersResult = withWindowIdFetchInit(
    sameOriginRequest,
    {headers: {Accept: 'application/json'}},
    windowId,
    currentHref,
);

assert.equal(
    requestInitHeadersResult.headers.get('Accept'),
    'application/json',
    'Les en-têtes passés dans init doivent conserver leur priorité sur ceux du Request.',
);

const externalInit = {
    headers: {
        Accept: 'application/x-protobuf',
    },
};
const externalResult = withWindowIdFetchInit(
    'https://data.geopf.fr/tms/1.0.0/PLAN.IGN/0/0/0.pbf',
    externalInit,
    windowId,
    currentHref,
);

assert.equal(
    externalResult,
    externalInit,
    'Une requête externe doit conserver exactement ses options fetch.',
);
assert.equal(
    new Headers(externalResult.headers).has('X-Window-Id'),
    false,
    'X-Window-Id ne doit jamais être envoyé à IGN.',
);

const externalRequest = new Request(
    'https://data.geopf.fr/tms/1.0.0/PLAN.IGN/0/0/0.pbf',
    {
        headers: {
            Accept: 'application/x-protobuf',
        },
    },
);
const externalRequestInit = {};
const externalRequestResult = withWindowIdFetchInit(
    externalRequest,
    externalRequestInit,
    windowId,
    currentHref,
);

assert.equal(externalRequestResult, externalRequestInit);
assert.equal(externalRequest.headers.get('Accept'), 'application/x-protobuf');
assert.equal(externalRequest.headers.has('X-Window-Id'), false);

const crossRealmExternalInit = {};
assert.equal(
    withWindowIdFetchInit(
        crossRealmExternalRequest,
        crossRealmExternalInit,
        windowId,
        currentHref,
    ),
    crossRealmExternalInit,
);

const noWindowIdInit = {headers: {Accept: 'application/json'}};
assert.equal(
    withWindowIdFetchInit('/api/cart', noWindowIdInit, null, currentHref),
    noWindowIdInit,
    'Sans identifiant de fenêtre, les options fetch doivent rester inchangées.',
);

const turboHeaders = {Accept: 'text/vnd.turbo-stream.html'};
const sameOriginTurboHeaders = addWindowIdToTurboHeaders(
    new URL('/checkout', currentHref),
    turboHeaders,
    windowId,
    currentHref,
);

assert.equal(
    sameOriginTurboHeaders.Accept,
    'text/vnd.turbo-stream.html',
);
assert.equal(
    sameOriginTurboHeaders['X-Window-Id'],
    windowId,
);
assert.equal(
    sameOriginTurboHeaders,
    turboHeaders,
    'La forme de l’objet headers fourni par Turbo doit être conservée.',
);

const headersInstance = new Headers({Accept: 'text/html'});
assert.equal(
    addWindowIdToTurboHeaders(
        new URL('/checkout', currentHref),
        headersInstance,
        windowId,
        currentHref,
    ),
    headersInstance,
);
assert.equal(headersInstance.get('X-Window-Id'), windowId);

const externalHeaders = {Accept: 'text/vnd.turbo-stream.html'};
const externalTurboHeaders = addWindowIdToTurboHeaders(
    new URL('https://data.geopf.fr/'),
    externalHeaders,
    windowId,
    currentHref,
);

assert.equal(
    externalTurboHeaders,
    externalHeaders,
    'Les en-têtes Turbo externes doivent rester inchangés.',
);
assert.equal(
    externalHeaders['X-Window-Id'],
    undefined,
);
assert.equal(
    addWindowIdToTurboHeaders(
        new URL('/checkout', currentHref),
        turboHeaders,
        null,
        currentHref,
    ),
    turboHeaders,
    'Sans identifiant de fenêtre, les en-têtes Turbo doivent rester inchangés.',
);

console.log(
    'OK — X-Window-Id est limité aux requêtes de même origine.',
);
