const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const vm = require('node:vm');

const root = path.join(__dirname, '..');

function response(data) {
    return {
        headers: { get: () => '' },
        ok: true,
        status: 200,
        statusText: 'OK',
        text: () => Promise.resolve(JSON.stringify({ code: 'OK', data })),
    };
}

function browser(search = '') {
    const requests = [];
    const attributes = new Map();
    const storage = new Map();
    const location = {
        hash: '',
        hostname: 'h5.global-interaction.com',
        href: `https://h5.global-interaction.com/guild/fami/host-center/${search}`,
        origin: 'https://h5.global-interaction.com',
        pathname: '/guild/fami/host-center/',
        search,
    };
    const window = {
        atob: (value) => Buffer.from(value, 'base64').toString('binary'),
        document: {
            documentElement: {
                setAttribute: (key, value) => attributes.set(key, value),
            },
        },
        dispatchEvent: () => {},
        fetch: (url, options = {}) => {
            requests.push({ url, options });
            return Promise.resolve(response({ ok: true }));
        },
        localStorage: {
            getItem: (key) => storage.get(key) || null,
            removeItem: (key) => storage.delete(key),
            setItem: (key, value) => storage.set(key, String(value)),
        },
        location,
    };
    window.window = window;
    window.URL = URL;
    window.URLSearchParams = URLSearchParams;
    const context = vm.createContext({
        Buffer,
        CustomEvent: function CustomEvent() {},
        Date,
        Error,
        FormData,
        JSON,
        Math,
        Number,
        Object,
        Promise,
        String,
        URL,
        URLSearchParams,
        console,
        document: window.document,
        window,
    });
    return { attributes, context, requests, window };
}

function runScript(context, relativePath) {
    const source = fs.readFileSync(path.join(root, relativePath), 'utf8');
    vm.runInContext(source, context, { filename: relativePath });
}

async function requestAppCode({ product, search = '' }) {
    const harness = browser(search);
    if (product) {
        runScript(harness.context, 'guild/packages/core/product-context.js');
        runScript(harness.context, `guild/products/${product}/product.js`);
    }
    runScript(harness.context, 'common/api.js');
    await harness.window.HyAppAPI.get('/api/v1/test');
    return {
        harness,
        appCode: harness.requests[0].options.headers['X-App-Code'],
    };
}

async function main() {
    const legacy = await requestAppCode({ product: '' });
    assert.equal(legacy.appCode, 'lalu', 'legacy pages must stay on Lalu');

    const fami = await requestAppCode({ product: 'fami' });
    assert.equal(fami.appCode, 'fami', 'Fami page default must be isolated');
    assert.equal(fami.harness.window.HyAppAPI.getAppCode(), 'fami');
    assert.equal(fami.harness.attributes.get('data-hy-product'), 'fami');

    const explicit = await requestAppCode({
        product: 'fami',
        search: '?app_code=lalu&env=test',
    });
    assert.equal(
        explicit.appCode,
        'lalu',
        'explicit diagnostic tenant must win over the page default'
    );

    const contextHarness = browser('?token=secret&env=test&language=ar&page=8');
    runScript(contextHarness.context, 'guild/packages/core/product-context.js');
    runScript(contextHarness.context, 'guild/products/fami/product.js');
    const linked = new URL(
        contextHarness.window.HyGuild.product.buildURL('../wallet/', {
            mode: 'usdt',
        })
    );
    assert.equal(linked.searchParams.get('app_code'), 'fami');
    assert.equal(linked.searchParams.get('token'), 'secret');
    assert.equal(linked.searchParams.get('env'), 'test');
    assert.equal(linked.searchParams.get('language'), 'ar');
    assert.equal(linked.searchParams.get('mode'), 'usdt');
    assert.equal(linked.searchParams.has('page'), false);

    const rangeHarness = browser();
    runScript(rangeHarness.context, 'guild/packages/core/date-range.js');
    const ranges = rangeHarness.window.HyGuild.dateRange;
    assert.equal(
        JSON.stringify(
            ranges.create('last_7_days', { now: new Date(2026, 6, 12) })
        ),
        JSON.stringify({
            preset: 'last_7_days',
            startDate: '2026-07-06',
            endDate: '2026-07-12',
        })
    );
    assert.equal(
        JSON.stringify(
            ranges.create('last_month', { now: new Date(2026, 0, 15) })
        ),
        JSON.stringify({
            preset: 'last_month',
            startDate: '2025-12-01',
            endDate: '2025-12-31',
        })
    );
    assert.throws(
        () =>
            ranges.create('custom', { start: '2026-07-12', end: '2026-07-01' }),
        /Invalid custom date range/
    );

    console.log('guild product architecture tests passed');
}

main().catch((error) => {
    console.error(error);
    process.exitCode = 1;
});
