import assert from 'node:assert/strict';
import { config } from '../src/config/index.js';
import { AlpacaConnector } from '../src/connectors/alpaca.js';
import {
    buildAlpacaSubTag,
    shouldAttachAlpacaSubTag,
    subTagBelongsToProfile,
    subTagHintsTrade
} from '../src/utils/alpacaSubTag.js';

const normalizeError = (reason: unknown): Error => {
    if (reason instanceof Error) return reason;
    if (reason && typeof reason === 'object') return new Error(JSON.stringify(reason));
    return new Error(String(reason ?? 'Unknown error'));
};

process.on('unhandledRejection', (reason) => {
    const err = normalizeError(reason);
    console.error('[alpaca-subtag] unhandled rejection', err);
    process.exit(1);
});

process.on('uncaughtException', (error) => {
    const err = normalizeError(error);
    console.error('[alpaca-subtag] uncaught exception', err);
    process.exit(1);
});

const originalConfig = {
    ENABLE_ALPACA_SUBTAG: config.ENABLE_ALPACA_SUBTAG,
    SUBTAG_OMNIBUS_ONLY: config.SUBTAG_OMNIBUS_ONLY,
    ALPACA_SUBTAG_ENV: config.ALPACA_SUBTAG_ENV,
    ALPACA_SUBTAG_MAX_LENGTH: config.ALPACA_SUBTAG_MAX_LENGTH,
    ALPACA_SUBTAG_DISABLE_FOR_EXCHANGE: [...(config.ALPACA_SUBTAG_DISABLE_FOR_EXCHANGE || [])],
    ALPACA_OMNIBUS_PROFILE_ALLOWLIST: [...config.ALPACA_OMNIBUS_PROFILE_ALLOWLIST],
    EXECUTION_PROVIDER: config.EXECUTION_PROVIDER,
    EXCHANGE: config.EXCHANGE
};

const restoreConfig = () => {
    (config as any).ENABLE_ALPACA_SUBTAG = originalConfig.ENABLE_ALPACA_SUBTAG;
    (config as any).SUBTAG_OMNIBUS_ONLY = originalConfig.SUBTAG_OMNIBUS_ONLY;
    (config as any).ALPACA_SUBTAG_ENV = originalConfig.ALPACA_SUBTAG_ENV;
    (config as any).ALPACA_SUBTAG_MAX_LENGTH = originalConfig.ALPACA_SUBTAG_MAX_LENGTH;
    (config as any).ALPACA_SUBTAG_DISABLE_FOR_EXCHANGE = [...originalConfig.ALPACA_SUBTAG_DISABLE_FOR_EXCHANGE];
    (config as any).ALPACA_OMNIBUS_PROFILE_ALLOWLIST = [...originalConfig.ALPACA_OMNIBUS_PROFILE_ALLOWLIST];
    (config as any).EXECUTION_PROVIDER = originalConfig.EXECUTION_PROVIDER;
    (config as any).EXCHANGE = originalConfig.EXCHANGE;
};

const testHelperDeterminism = () => {
    const profileId = '503f4da8-e063-4583-9f30-0cc22ede9ff4';
    const tradeId = 'TRD-0cc22ede9ff4-SOLUSDT-BUY-1771637085052-000004';

    const a = buildAlpacaSubTag({ profileId, tradeId, intent: 'ENTRY' });
    const b = buildAlpacaSubTag({ profileId, tradeId, intent: 'ENTRY' });

    assert.ok(a, 'sub-tag should be produced');
    assert.equal(a, b, 'sub-tag must be deterministic');
    assert.ok((a as string).startsWith('BL:'), 'sub-tag should use BL prefix');
    assert.ok((a as string).length <= Number(config.ALPACA_SUBTAG_MAX_LENGTH || 48), 'sub-tag should respect max length');

    assert.equal(subTagBelongsToProfile(a as string, profileId), true, 'sub-tag should map to correct profile');
    assert.equal(subTagBelongsToProfile(a as string, '11111111-1111-1111-1111-111111111111'), false, 'sub-tag should not map to another profile');
    assert.equal(subTagHintsTrade(a as string, tradeId), true, 'sub-tag should map to correct trade');
    assert.equal(subTagHintsTrade(a as string, 'TRD-OTHER'), false, 'sub-tag should not map to another trade');
};

const testFeatureGating = () => {
    const profileId = '503f4da8-e063-4583-9f30-0cc22ede9ff4';

    (config as any).EXECUTION_PROVIDER = 'alpaca';
    (config as any).EXCHANGE = 'kraken';
    (config as any).ENABLE_ALPACA_SUBTAG = false;
    (config as any).SUBTAG_OMNIBUS_ONLY = true;
    (config as any).ALPACA_SUBTAG_DISABLE_FOR_EXCHANGE = [];
    (config as any).ALPACA_OMNIBUS_PROFILE_ALLOWLIST = [];
    assert.equal(shouldAttachAlpacaSubTag({ profileId }), false, 'feature disabled should block sub-tagging');

    (config as any).ENABLE_ALPACA_SUBTAG = true;
    (config as any).SUBTAG_OMNIBUS_ONLY = false;
    assert.equal(shouldAttachAlpacaSubTag({ profileId }), true, 'omnibus-only disabled should allow sub-tagging');

    (config as any).ALPACA_SUBTAG_DISABLE_FOR_EXCHANGE = ['kraken', 'binance'];
    assert.equal(
        shouldAttachAlpacaSubTag({ profileId }),
        true,
        'disable list should not block when execution provider is alpaca'
    );

    (config as any).ALPACA_SUBTAG_DISABLE_FOR_EXCHANGE = ['alpaca'];
    assert.equal(shouldAttachAlpacaSubTag({ profileId }), false, 'disable list should block alpaca when configured');

    (config as any).ALPACA_SUBTAG_DISABLE_FOR_EXCHANGE = [];
    (config as any).SUBTAG_OMNIBUS_ONLY = true;
    assert.equal(shouldAttachAlpacaSubTag({ profileId }), false, 'missing omnibus flag should block when omnibus-only');

    assert.equal(
        shouldAttachAlpacaSubTag({
            profileId,
            profileSettings: { strategy_config: { execution: { mode: 'omnibus' } } }
        }),
        true,
        'profile omnibus mode should allow sub-tagging'
    );

    (config as any).ALPACA_OMNIBUS_PROFILE_ALLOWLIST = [profileId];
    assert.equal(shouldAttachAlpacaSubTag({ profileId }), true, 'allowlisted profile should allow sub-tagging');
};

const testConnectorPayload = async () => {
    const connector = new AlpacaConnector('test-key', 'test-secret');
    const capturedOrders: any[] = [];
    (connector as any).client = {
        createOrder: async (payload: any) => {
            capturedOrders.push({ ...payload });
            return {
                id: `MOCK-${capturedOrders.length}`,
                status: 'accepted'
            };
        }
    };

    const withSubTag = await connector.placeOrder(
        'SOL/USD',
        'buy',
        0.5,
        'market',
        undefined,
        undefined,
        undefined,
        'client-1',
        { subTag: 'BL:PAPER:PABC:TABC:ENTRY' }
    );
    assert.equal(capturedOrders[0].client_order_id, 'client-1', 'client_order_id should pass through');
    assert.equal(capturedOrders[0].subtag, 'BL:PAPER:PABC:TABC:ENTRY', 'sub-tag should be attached when provided');
    assert.equal(withSubTag.subtag, 'BL:PAPER:PABC:TABC:ENTRY', 'connector should keep sub-tag on returned order');

    await connector.placeOrder('SOL/USD', 'sell', 0.5, 'market');
    assert.equal(capturedOrders[1].subtag, undefined, 'sub-tag must be absent when not provided');
};

async function run() {
    try {
        (config as any).ALPACA_SUBTAG_ENV = 'paper';
        (config as any).ALPACA_SUBTAG_MAX_LENGTH = 48;

        testHelperDeterminism();
        testFeatureGating();
        await testConnectorPayload();
        console.log('[alpaca-subtag] OK: helper, gating, and connector payload checks passed');
    } finally {
        restoreConfig();
    }
}

await run();
