
import { supabaseService } from '../src/services/SupabaseService.js';
import { AutoTrader } from '../src/services/AutoTrader.js';
import { TradeExecutor } from '../src/services/TradeExecutor.js';
import { AlpacaConnector } from '../src/connectors/alpaca.js';
import { config } from '../src/config/index.js';
import { SignalDirection, MarketContext, RuleResult, StrategyAnalysisResult } from '../src/strategies/rules/types.js';
import logger from '../src/utils/logger.js';

// Setup environment and global config overrides for testing
config.ENABLE_TRADING = true;
// Force Paper Trading for safety
config.PAPER_TRADING = true;

const TEST_SYMBOL = 'BTC/USD'; // Alpaca Paper usually supports this for crypto
const SLEEP_MS = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));

async function runFullE2ETest() {
    logger.info('===================================================');
    logger.info('🚀 STARTING END-TO-END BACKEND SYSTEM TEST');
    logger.info('   Scope: Configs -> Signal -> Order -> Position -> DB -> Exit -> PnL');
    logger.info('===================================================');

    // 1. Load Profiles (Simulating "Multiple Configurations")
    logger.info('\n📡 1. Loading Configurations from Database...');
    const profiles = await supabaseService.getActiveProfiles();

    if (profiles.length === 0) {
        logger.error('❌ No active profiles found in DB. Please create a Strategy Cluster in the Dashboard first.');
        process.exit(1);
    }
    logger.info(`✅ Found ${profiles.length} Active Profiles.`);

    // 2. Iterate Profiles and Execute Test Cycle
    for (const profile of profiles) {
        logger.info(`\n---------------------------------------------------`);
        logger.info(`👤 Testing Profile: [${profile.name}] (ID: ${profile.id})`);
        logger.info(`   Allocated Capital: $${profile.allocated_capital}`);
        logger.info(`   Risk Per Trade: ${profile.risk_per_trade_percent}%`);

        const user = profile.users;
        if (!user) {
            logger.warn('   ⚠️ User data missing for this profile. Skipping.');
            continue;
        }

        // Initialize Services for this specific User/Profile
        const userKey = config.PAPER_TRADING ? user.ALPACA_API_KEY : user.REAL_ALPACA_API_KEY;
        const userSecret = config.PAPER_TRADING ? user.ALPACA_SECRET_KEY : user.REAL_ALPACA_SECRET_KEY;

        if (!userKey || !userSecret) {
            logger.warn('   ⚠️ Alpaca Credentials missing. Skipping.');
            continue;
        }

        const exchange = new AlpacaConnector(userKey, userSecret);
        const executor = new TradeExecutor(exchange, undefined, user.user_id, profile.id);
        const trader = new AutoTrader(executor, exchange, profile);

        // SYNC: Ensure we start clean
        logger.info('   🔄 Syncing existing positions...');
        await executor.syncPositions([TEST_SYMBOL]);

        // Close any existing position on Test Symbol to ensure clean test
        const existingPos = executor.getActivePosition(TEST_SYMBOL);
        if (existingPos) {
            logger.info(`   🧹 Closing pre-existing position on ${TEST_SYMBOL}...`);
            await executor.closePosition(TEST_SYMBOL, 'E2E PRE-CLEANUP');
            await SLEEP_MS(5000);
        }

        // 3. Simulate Market Context
        const currentPrice = 65000;
        const mockContext: MarketContext = {
            symbol: TEST_SYMBOL,
            currentPrice: currentPrice,
            candles1h: [], candles15m: [], candles4h: [],
            rsi_1h: 30, // Oversold
            ema20_1h: 64000,
            change24h: 1.5,
            changeToday: 0.5,
            volatility: 'Low',
            session: 'NY',
            isMajorSession: true,
            latestSignal: SignalDirection.NONE
        };

        // 4. Simulate BUY Signal
        logger.info('   🟢 Simulating BUY Signal (Trend + Momentum)...');

        // Construct Analysis Result that passes "Logic"
        // We ensure a 'generic' passing rule if the profile has specific rules, or rely on global if none.
        const ruleResults: Record<string, RuleResult> = {};

        // Mock common rules to PASS
        const rulesToMock = ['TrendBiasRule', 'MomentumRule', 'ZoneRule', 'RiskManagementRule'];
        rulesToMock.forEach(rId => {
            ruleResults[rId] = { ruleName: rId, passed: true, signal: SignalDirection.BUY, reason: 'Test Pass', metadata: {} };
        });

        const buyAnalysis: StrategyAnalysisResult = {
            symbol: TEST_SYMBOL,
            globalSignal: SignalDirection.BUY,
            rules: ruleResults,
            context: mockContext
        };

        await trader.handleSignal(TEST_SYMBOL, buyAnalysis);

        // 5. Verify Order & Position Creation
        logger.info('   ⏳ Waiting for Order Fill & DB Sync (10s)...');
        await SLEEP_MS(10000); // Wait for API calls and DB events

        const activePos = executor.getActivePosition(TEST_SYMBOL);
        if (!activePos) {
            logger.error(`   ❌ FAIL: Position not created for ${profile.name}`);
            continue; // Skip to next profile
        }

        logger.info(`   ✅ SUCCESS: Position Created!`);
        logger.info(`      Qty: ${activePos.size}`);
        logger.info(`      Entry: ${activePos.entryPrice}`);
        logger.info(`      Initial U.PnL: ${activePos.unrealizedPnl}`);

        // Check DB for Order
        const latestOrder = await supabaseService.getLatestOrder(user.user_id, TEST_SYMBOL);
        if (latestOrder && latestOrder.side === 'buy' && latestOrder.status === 'filled') {
            logger.info(`   ✅ DB VERIFIED: Buy Order ${latestOrder.order_id} recorded.`);
        } else {
            logger.warn(`   ⚠️ DB WARNING: Could not find recent filled buy order.`);
        }

        // 6. Simulate Profit Update (Price Move Up)
        logger.info('   📈 Simulating Price Move (+10%)...');
        const newPrice = currentPrice * 1.10;
        mockContext.currentPrice = newPrice;

        // 7. Simulate SELL/EXIT Signal
        logger.info('   🔴 Simulating SELL/EXIT Signal (Trend Reversal)...');
        const sellAnalysis: StrategyAnalysisResult = {
            symbol: TEST_SYMBOL,
            globalSignal: SignalDirection.SELL, // Reversal triggers exit
            rules: ruleResults,
            context: mockContext
        };

        await trader.handleSignal(TEST_SYMBOL, sellAnalysis);

        // 8. Verify Exit & PnL Realization
        logger.info('   ⏳ Waiting for Close & Profit Realization (10s)...');
        await SLEEP_MS(10000);

        const closedPos = executor.getActivePosition(TEST_SYMBOL);
        if (!closedPos) {
            logger.info(`   ✅ SUCCESS: Position Closed.`);
        } else {
            logger.error(`   ❌ FAIL: Position still active!`);
        }

        // Check DB for Trade History (PnL)
        // We verify the 'logTransaction' was called
        // Since we don't have a direct 'getLatestTransaction', we infer success from logs or check orders
        const sellOrder = await supabaseService.getLatestOrder(user.user_id, TEST_SYMBOL);
        if (sellOrder && sellOrder.side === 'sell' && sellOrder.status === 'filled') {
            logger.info(`   ✅ DB VERIFIED: Sell Order ${sellOrder.order_id} recorded.`);
            // In a real scenario, we'd query trade_history too, but logged orders confirms the loop.
        }

        logger.info(`   🎉 Profile [${profile.name}] Test Cycle Complete.`);
    }

    logger.info('\n===================================================');
    logger.info('✅ E2E TEST SUITE COMPLETED');
    logger.info('===================================================');
    process.exit(0);
}

runFullE2ETest().catch(err => {
    logger.error('CRITICAL TEST FAILURE:', err);
    process.exit(1);
});
