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 apiResponse(data) {
    return {
        headers: { get: () => '' },
        ok: true,
        status: 200,
        statusText: 'OK',
        text: () => Promise.resolve(JSON.stringify({ code: 'OK', data })),
    };
}
function harness(search = '') {
    const requests = [];
    const storage = new Map();
    const location = {
        hash: '',
        hostname: 'h5.global-interaction.com',
        href: `https://h5.global-interaction.com/guild/fami/wallet/${search}`,
        origin: 'https://h5.global-interaction.com',
        pathname: '/guild/fami/wallet/',
        search,
    };
    const window = {
        atob: (value) => Buffer.from(value, 'base64').toString('binary'),
        crypto: { randomUUID: () => 'fixed-uuid' },
        document: {
            currentScript: null,
            documentElement: { setAttribute: () => {} },
        },
        dispatchEvent: () => {},
        fetch: (rawURL, options = {}) => {
            const url = new URL(rawURL);
            requests.push({ url, options });
            if (url.pathname === '/api/v1/point-wallet/overview') {
                return Promise.resolve(
                    apiResponse({
                        balance: {
                            available_amount: 2000000,
                            display_usd: '20.00',
                        },
                        points_per_usd: 100000,
                        fee_bps: 500,
                        minimum_points: 1000000,
                        coin_sellers: [
                            {
                                user_id: '9007199254740001',
                                display_user_id: '443344',
                                nickname: 'Seller',
                                point_amount: 100000,
                                seller_coin_amount: 92000,
                            },
                        ],
                    })
                );
            }
            if (url.pathname === '/api/v1/wallet/transactions') {
                return Promise.resolve(
                    apiResponse({
                        transactions: [
                            {
                                transaction_id: 'tx-1',
                                biz_type: 'point_transfer_to_coin_seller',
                                available_delta: -1000000,
                            },
                        ],
                    })
                );
            }
            return Promise.resolve(apiResponse({}));
        },
        localStorage: {
            getItem: (key) => storage.get(key) || null,
            removeItem: (key) => storage.delete(key),
            setItem: (key, value) => storage.set(key, String(value)),
        },
        location,
    };
    window.window = window;
    return {
        context: vm.createContext({
            Buffer,
            CustomEvent: function CustomEvent() {},
            Date,
            Error,
            FormData,
            JSON,
            Math,
            Number,
            Object,
            Promise,
            String,
            URL,
            URLSearchParams,
            console,
            document: window.document,
            window,
        }),
        requests,
        window,
    };
}
function run(context, file) {
    vm.runInContext(fs.readFileSync(path.join(root, file), 'utf8'), context, {
        filename: file,
    });
}

async function main() {
    const browser = harness('?token=test-token&env=test');
    run(browser.context, 'guild/packages/core/product-context.js');
    run(browser.context, 'guild/products/fami/product.js');
    run(browser.context, 'common/api.js');
    run(browser.context, 'guild/packages/wallet/wallet.js');
    const data = await browser.window.HyGuild.wallet.load();
    assert.equal(data.balance.available, 2000000);
    assert.equal(data.sellers[0].userId, '9007199254740001');
    assert.equal(data.sellers[0].sellerCoinAmount, 92000);
    assert.equal(data.history[0].bizType, 'point_transfer_to_coin_seller');
    await browser.window.HyGuild.wallet.transferToCoinSeller(
        data.sellers[0].userId,
        1000000
    );
    const transfer = browser.requests.find(
        ({ url }) =>
            url.pathname === '/api/v1/point-wallet/transfer-to-coin-seller'
    );
    assert.deepEqual(JSON.parse(transfer.options.body), {
        command_id: 'fami-point-coin-seller:fixed-uuid',
        seller_user_id: '9007199254740001',
        point_amount: 1000000,
    });
    browser.requests.forEach(({ options }) =>
        assert.equal(options.headers['X-App-Code'], 'fami')
    );

    const mockBrowser = harness('?mock=1');
    run(mockBrowser.context, 'guild/packages/core/product-context.js');
    run(mockBrowser.context, 'guild/products/fami/product.js');
    run(mockBrowser.context, 'guild/packages/wallet/wallet.js');
    const mock = await mockBrowser.window.HyGuild.wallet.load();
    assert.equal(mock.sellers.length, 2);
    assert.equal(mockBrowser.requests.length, 0);
    console.log('Fami wallet tests passed');
}

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