import assert from 'node:assert/strict';
import { ManualTrader } from '../src/services/ManualTrader.js';
import { SignalDirection } from '../src/strategies/rules/types.js';
import { supabaseService } from '../src/services/SupabaseService.js';

class MockExecutor {
    public positions = new Map<string, any>();
    public calls: Array<{ symbol: string; side: SignalDirection; qty: number; type: 'market' | 'limit'; price?: number }> = [];

    getAllPositions() {
        return this.positions;
    }

    getProfileId() {
        return 'profile-cap-1';
    }

    getUserId() {
        return 'user-cap-1';
    }

    getActivePosition(_symbol: string) {
        return null;
    }

    async closePosition(_symbol: string, _reason: string) {
        return { success: true };
    }

    async openPosition(
        symbol: string,
        side: SignalDirection,
        qty: number,
        type: 'market' | 'limit',
        price?: number
    ) {
        this.calls.push({ symbol, side, qty, type, price });
        return { success: true, orderId: `mock-${Date.now()}` };
    }
}

async function testScaleToRemainingCapital() {
    const executor = new MockExecutor();
    executor.positions.set('BTC/USD', {
        entryPrice: 100,
        size: 9 // committed = 900
    });

    const trader = new ManualTrader(executor as any);
    const result = await trader.executeRequest('ETH/USD', 'buy', 2, 'market', undefined, 100, 'user-cap-1');

    assert.equal(result.success, true, 'Manual trade should succeed when some capital remains.');
    assert.equal(Number(result.adjustedQty), 1, 'Quantity should be reduced to remaining capital capacity.');
    assert.equal(executor.calls.length, 1, 'openPosition should be called once.');
    assert.equal(Number(executor.calls[0].qty), 1, 'Executor should receive scaled quantity.');
}

async function testWaitForCapitalRelease() {
    const executor = new MockExecutor();
    executor.positions.set('BTC/USD', {
        entryPrice: 100,
        size: 10 // committed = 1000, no immediate room
    });

    const trader = new ManualTrader(executor as any);

    setTimeout(() => {
        executor.positions.set('BTC/USD', {
            entryPrice: 100,
            size: 9 // remaining = 100 after release
        });
    }, 1200);

    const start = Date.now();
    const result = await trader.executeRequest('SOL/USD', 'buy', 1, 'market', undefined, 100, 'user-cap-1');
    const elapsed = Date.now() - start;

    assert.equal(result.success, true, 'Manual trade should proceed once capital is released.');
    assert(elapsed >= 1000, 'Manual trader should wait for capital release window.');
    assert.equal(executor.calls.length, 1, 'openPosition should execute after wait.');
    assert.equal(Number(executor.calls[0].qty), 1, 'Released capital should allow requested quantity.');
}

async function run() {
    const originalGetProfileCapital = (supabaseService as any).getProfileCapital;
    (supabaseService as any).getProfileCapital = async () => ({
        allocatedCapital: 1000,
        isActive: true,
        userId: 'user-cap-1'
    });

    try {
        await testScaleToRemainingCapital();
        await testWaitForCapitalRelease();
    } finally {
        (supabaseService as any).getProfileCapital = originalGetProfileCapital;
    }

    console.log('[manual-capital-guard] OK: scale-to-remaining and wait-for-release paths validated');
}

await run();
