/home/devscfvi/web.devsquantum.com/js/import.js
// ============================================
// TRADE IMPORT MODULE
// ============================================

const importState = {
    format: 'app',      // 'app' | 'binance' | 'coinbase' | 'ibkr'
    parsedTrades: [],
    fileName: null,
    rawText: ''
};

// ============================================
// RENDER IMPORT VIEW
// ============================================

function renderImport() {
    const terms = getTerms();
    return `
        <div class="min-h-screen p-4 md:p-6">
            <div class="max-w-3xl mx-auto">

                <!-- Header -->
                <div class="flex items-center justify-between mb-6 pt-4">
                    <div>
                        <h1 class="text-2xl font-bold text-white">Import Trades</h1>
                        <p class="text-sm text-violet-300">Import from CSV or exchange export</p>
                    </div>
                    <button onclick="navigateTo('more')"
                        class="bg-violet-600 hover:bg-violet-700 text-white px-4 py-3 rounded-xl shadow-lg active:scale-95 transition font-medium">
                        Back
                    </button>
                </div>

                <div class="space-y-4">

                    <!-- Step 1: Format Selection -->
                    <div class="glass rounded-3xl p-6 border border-violet-500/20">
                        <div class="flex items-center gap-2 mb-4">
                            <div class="w-6 h-6 rounded-full gradient-bg flex items-center justify-center text-xs font-bold text-white">1</div>
                            <h3 class="text-lg font-semibold text-white">Choose Import Format</h3>
                        </div>

                        <div class="space-y-2">
                            <button onclick="selectImportFormat('app')" id="format-btn-app"
                                class="import-format-btn w-full text-left p-4 rounded-xl border transition active:scale-[0.99]
                                    ${importState.format === 'app'
                                        ? 'border-violet-500 bg-violet-500/15'
                                        : 'border-violet-500/20 bg-slate-900/50 hover:border-violet-500/50'}">
                                <div class="flex items-center gap-3">
                                    <span class="text-2xl">๐Ÿ“Š</span>
                                    <div>
                                        <div class="font-semibold text-white">App Export CSV</div>
                                        <div class="text-xs text-slate-400 mt-0.5">Re-import trades exported from this app</div>
                                    </div>
                                    ${importState.format === 'app' ? '<svg class="w-5 h-5 text-violet-400 ml-auto flex-shrink-0" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/></svg>' : ''}
                                </div>
                            </button>

                            <button onclick="selectImportFormat('binance')" id="format-btn-binance"
                                class="import-format-btn w-full text-left p-4 rounded-xl border transition active:scale-[0.99]
                                    ${importState.format === 'binance'
                                        ? 'border-yellow-500 bg-yellow-500/10'
                                        : 'border-violet-500/20 bg-slate-900/50 hover:border-violet-500/50'}">
                                <div class="flex items-center gap-3">
                                    <span class="text-2xl">๐ŸŸก</span>
                                    <div>
                                        <div class="font-semibold text-white">Binance Trade History</div>
                                        <div class="text-xs text-slate-400 mt-0.5">Orders โ†’ Trade History โ†’ Export โ†’ CSV</div>
                                    </div>
                                    ${importState.format === 'binance' ? '<svg class="w-5 h-5 text-yellow-400 ml-auto flex-shrink-0" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/></svg>' : ''}
                                </div>
                            </button>

                            <button onclick="selectImportFormat('coinbase')" id="format-btn-coinbase"
                                class="import-format-btn w-full text-left p-4 rounded-xl border transition active:scale-[0.99]
                                    ${importState.format === 'coinbase'
                                        ? 'border-blue-500 bg-blue-500/10'
                                        : 'border-violet-500/20 bg-slate-900/50 hover:border-violet-500/50'}">
                                <div class="flex items-center gap-3">
                                    <span class="text-2xl">๐Ÿ”ต</span>
                                    <div>
                                        <div class="font-semibold text-white">Coinbase Transaction History</div>
                                        <div class="text-xs text-slate-400 mt-0.5">Reports โ†’ Generate Report โ†’ CSV</div>
                                    </div>
                                    ${importState.format === 'coinbase' ? '<svg class="w-5 h-5 text-blue-400 ml-auto flex-shrink-0" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/></svg>' : ''}
                                </div>
                            </button>

                            <button onclick="selectImportFormat('ibkr')" id="format-btn-ibkr"
                                class="import-format-btn w-full text-left p-4 rounded-xl border transition active:scale-[0.99]
                                    ${importState.format === 'ibkr'
                                        ? 'border-orange-500 bg-orange-500/10'
                                        : 'border-violet-500/20 bg-slate-900/50 hover:border-violet-500/50'}">
                                <div class="flex items-center gap-3">
                                    <span class="text-2xl">๐ŸŸ </span>
                                    <div>
                                        <div class="font-semibold text-white">IBKR โ€” Transaction History CSV</div>
                                        <div class="text-xs text-slate-400 mt-0.5">Reports โ†’ Activity โ†’ Transaction History โ†’ Download</div>
                                    </div>
                                    ${importState.format === 'ibkr' ? '<svg class="w-5 h-5 text-orange-400 ml-auto flex-shrink-0" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/></svg>' : ''}
                                </div>
                            </button>

                            <button onclick="selectImportFormat('ibkr-tlg')" id="format-btn-ibkr-tlg"
                                class="import-format-btn w-full text-left p-4 rounded-xl border transition active:scale-[0.99]
                                    ${importState.format === 'ibkr-tlg'
                                        ? 'border-orange-400 bg-orange-400/10'
                                        : 'border-violet-500/20 bg-slate-900/50 hover:border-violet-500/50'}">
                                <div class="flex items-center gap-3">
                                    <span class="text-2xl">๐Ÿ”ถ</span>
                                    <div>
                                        <div class="font-semibold text-white">IBKR โ€” .tlg File <span class="text-xs bg-green-500/20 text-green-300 px-1.5 py-0.5 rounded ml-1">Recommended</span></div>
                                        <div class="text-xs text-slate-400 mt-0.5">Reports โ†’ Activity โ†’ Trades โ†’ Export as .tlg (TraderVue format)</div>
                                    </div>
                                    ${importState.format === 'ibkr-tlg' ? '<svg class="w-5 h-5 text-orange-300 ml-auto flex-shrink-0" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/></svg>' : ''}
                                </div>
                            </button>
                        </div>
                    </div>

                    <!-- Step 2: File Upload -->
                    <div class="glass rounded-3xl p-6 border border-violet-500/20">
                        <div class="flex items-center gap-2 mb-4">
                            <div class="w-6 h-6 rounded-full gradient-bg flex items-center justify-center text-xs font-bold text-white">2</div>
                            <h3 class="text-lg font-semibold text-white">Upload CSV File</h3>
                        </div>

                        <input type="file" id="import-file-input" accept=".csv,.txt,.tlg"
                            onchange="handleImportFile(this)" class="hidden">

                        <div onclick="document.getElementById('import-file-input').click()"
                            class="border-2 border-dashed border-violet-500/30 rounded-xl p-8 text-center cursor-pointer hover:border-violet-400/60 transition group">
                            <svg class="w-12 h-12 mx-auto text-violet-400/40 group-hover:text-violet-400/60 mb-3 transition" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"></path>
                            </svg>
                            <p id="import-file-label" class="text-slate-300 font-medium">
                                ${importState.fileName || 'Click to upload or drag & drop'}
                            </p>
                            <p class="text-xs text-slate-500 mt-1">CSV or .tlg files ยท Max 5MB</p>
                        </div>

                        ${importState.fileName ? `
                            <div class="mt-3 flex items-center gap-2 text-sm text-green-400">
                                <svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
                                    <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
                                </svg>
                                ${importState.fileName} loaded โ€” ${importState.parsedTrades.length} trade(s) found
                            </div>
                        ` : ''}
                    </div>

                    <!-- Step 3: Preview -->
                    <div id="import-preview"></div>

                </div>
            </div>
        </div>
    `;
}

// Select format and re-render
function selectImportFormat(fmt) {
    importState.format = fmt;
    // Re-parse if we already have raw text
    if (importState.rawText) {
        importState.parsedTrades = parseCSVFile(importState.rawText, fmt);
    }
    const app = document.getElementById('app');
    if (app) app.innerHTML = renderImport();
    renderImportPreview();
}

// Handle file selection
function handleImportFile(input) {
    if (!input.files || !input.files[0]) return;
    const file = input.files[0];
    if (file.size > 5 * 1024 * 1024) {
        showToast('File too large (max 5MB)', 'error');
        return;
    }
    importState.fileName = file.name;
    const reader = new FileReader();
    reader.onload = (e) => {
        importState.rawText = e.target.result;
        importState.parsedTrades = parseCSVFile(importState.rawText, importState.format);
        // Re-render page with updated state
        const app = document.getElementById('app');
        if (app) app.innerHTML = renderImport();
        renderImportPreview();
    };
    reader.readAsText(file);
}

// ============================================
// CSV PARSERS
// ============================================

function parseCSVFile(text, format) {
    switch (format) {
        case 'binance':    return parseBinanceCSV(text);
        case 'coinbase':   return parseCoinbaseCSV(text);
        case 'ibkr':       return parseIBKRCSV(text);
        case 'ibkr-tlg':   return parseIBKRTLGFile(text);
        default:           return parseAppExportCSV(text);
    }
}

// Parse a single CSV line (handles quoted fields)
function parseCSVLine(line) {
    const result = [];
    let inQuotes = false;
    let current = '';
    for (let i = 0; i < line.length; i++) {
        const ch = line[i];
        if (ch === '"') {
            inQuotes = !inQuotes;
        } else if (ch === ',' && !inQuotes) {
            result.push(current.trim());
            current = '';
        } else {
            current += ch;
        }
    }
    result.push(current.trim());
    return result;
}

// Parse all lines into array of row arrays
function parseCSVRows(text) {
    return text
        .split(/\r?\n/)
        .filter(l => l.trim().length > 0)
        .map(parseCSVLine);
}

// ---- App Export CSV Parser ----
// Headers: Date,Coin,Category,Order Type,Position,Entry,SL%,TP%,SL Price,TP Price,Max Loss,Max Profit,Fees,R:R,Status,Emotion,Discipline,Mistake,Comment
function parseAppExportCSV(text) {
    const rows = parseCSVRows(text);
    if (rows.length < 2) return [];
    const header = rows[0].map(h => h.toLowerCase().trim());
    const trades = [];

    const idx = (name) => header.findIndex(h => h.includes(name));
    const dateIdx   = Math.max(idx('date'), 0);
    const coinIdx   = idx('coin');
    const catIdx    = idx('category');
    const typeIdx   = idx('order');
    const posIdx    = idx('position');
    const entryIdx  = idx('entry');
    const slpIdx    = idx('sl%');
    const tpPIdx    = idx('tp%');
    const slIdx     = idx('sl price');
    const tpIdx     = idx('tp price');
    const lossIdx   = idx('max loss');
    const profIdx   = idx('max profit');
    const feeIdx    = idx('fee');
    const rrIdx     = idx('r:r');
    const statIdx   = idx('status');
    const emIdx     = idx('emotion');
    const miscIdx   = idx('mistake');
    const cmtIdx    = idx('comment');

    for (let i = 1; i < rows.length; i++) {
        const r = rows[i];
        if (r.length < 5) continue;
        trades.push({
            coin:              r[coinIdx]   || '',
            positionSize:      parseFloat(r[posIdx])   || 0,
            entryPrice:        parseFloat(r[entryIdx])  || 0,
            stopLossPercent:   parseFloat(r[slpIdx])   || 0,
            takeProfitPercent: parseFloat(r[tpPIdx])   || 0,
            slPrice:           parseFloat(r[slIdx])    || 0,
            tpPrice:           parseFloat(r[tpIdx])    || 0,
            lossAmount:        parseFloat(r[lossIdx])  || 0,
            profitAmount:      parseFloat(r[profIdx])  || 0,
            rewardRiskRatio:   parseFloat(r[rrIdx])    || 0,
            fees:              parseFloat(r[feeIdx])   || 0,
            orderType:         r[typeIdx]   || 'market',
            category:          r[catIdx]    || null,
            emotion:           r[emIdx]     || null,
            mistakeType:       r[miscIdx]   || null,
            comment:           r[cmtIdx]    || '',
            status:            r[statIdx]   || 'pending',
            quantity:          0
        });
    }
    return trades;
}

// ---- Binance CSV Parser ----
// Headers: Date(UTC),Pair,Side,Price,Executed,Amount,Fee
function parseBinanceCSV(text) {
    const rows = parseCSVRows(text);
    if (rows.length < 2) return [];
    const header = rows[0].map(h => h.toLowerCase().replace(/[^a-z]/g, ''));

    const findCol = (...names) => {
        for (const n of names) {
            const i = header.findIndex(h => h.includes(n));
            if (i >= 0) return i;
        }
        return -1;
    };

    const dateIdx   = findCol('date', 'time');
    const pairIdx   = findCol('pair', 'symbol', 'market');
    const sideIdx   = findCol('side', 'type', 'direction');
    const priceIdx  = findCol('price', 'avgprice');
    const execIdx   = findCol('executed', 'qty', 'quantity');
    const amtIdx    = findCol('amount', 'total', 'value');
    const feeIdx    = findCol('fee', 'commission');

    const stripNum  = (s) => parseFloat((s || '').toString().replace(/[^0-9.]/g, '')) || 0;
    const stripCoin = (pair) => {
        pair = (pair || '').toUpperCase();
        return pair
            .replace(/(USDT|BUSD|USDC|TUSD|BTC|ETH|BNB|USD)$/, '')
            || pair;
    };

    const trades = [];
    for (let i = 1; i < rows.length; i++) {
        const r = rows[i];
        if (r.length < 4) continue;
        const side = (r[sideIdx] || '').toUpperCase();
        if (side !== 'BUY') continue; // Only import BUY entries as new trade setups

        const coin         = stripCoin(r[pairIdx]);
        const entryPrice   = stripNum(r[priceIdx]);
        const positionSize = stripNum(r[amtIdx]);
        const quantity     = stripNum(r[execIdx]);
        const fees         = stripNum(r[feeIdx]);

        trades.push({
            coin,
            positionSize,
            entryPrice,
            stopLossPercent:   0,
            takeProfitPercent: 0,
            slPrice:           0,
            tpPrice:           0,
            lossAmount:        0,
            profitAmount:      0,
            rewardRiskRatio:   0,
            fees,
            quantity,
            orderType:  'market',
            category:   null,
            emotion:    null,
            mistakeType:null,
            comment:    `Imported from Binance โ€” ${r[dateIdx] || ''}`,
            status:     'pending'
        });
    }
    return trades;
}

// ---- Coinbase CSV Parser ----
// Headers: Timestamp,Transaction Type,Asset,Quantity Transacted,Spot Price Currency,Spot Price at Transaction,Subtotal,Total (inclusive of fees and/or spread),Fees and/or Spread,Notes
function parseCoinbaseCSV(text) {
    // Skip any leading metadata rows (Coinbase adds header info before the CSV header)
    const lines = text.split(/\r?\n/).filter(l => l.trim().length > 0);
    let headerIdx = lines.findIndex(l => l.toLowerCase().includes('timestamp') || l.toLowerCase().includes('transaction type'));
    if (headerIdx < 0) headerIdx = 0;

    const csvText = lines.slice(headerIdx).join('\n');
    const rows = parseCSVRows(csvText);
    if (rows.length < 2) return [];

    const header = rows[0].map(h => h.toLowerCase().trim());
    const findCol = (...names) => {
        for (const n of names) {
            const i = header.findIndex(h => h.includes(n));
            if (i >= 0) return i;
        }
        return -1;
    };

    const tsIdx     = findCol('timestamp', 'date');
    const typeIdx   = findCol('transaction type', 'type');
    const assetIdx  = findCol('asset', 'coin', 'currency');
    const qtyIdx    = findCol('quantity transacted', 'amount', 'quantity');
    const priceIdx  = findCol('spot price at transaction', 'price', 'spot price');
    const subtlIdx  = findCol('subtotal');
    const feeIdx    = findCol('fees', 'fee');

    const stripNum = (s) => parseFloat((s || '').toString().replace(/[^0-9.]/g, '')) || 0;

    const trades = [];
    for (let i = 1; i < rows.length; i++) {
        const r = rows[i];
        if (r.length < 4) continue;
        const txType = (r[typeIdx] || '').toLowerCase();
        if (!txType.includes('buy')) continue; // Only import Buy transactions

        const coin         = (r[assetIdx] || '').toUpperCase().trim();
        const entryPrice   = stripNum(r[priceIdx]);
        const quantity     = stripNum(r[qtyIdx]);
        const positionSize = subtlIdx >= 0 ? stripNum(r[subtlIdx]) : entryPrice * quantity;
        const fees         = stripNum(r[feeIdx]);

        trades.push({
            coin,
            positionSize,
            entryPrice,
            stopLossPercent:   0,
            takeProfitPercent: 0,
            slPrice:           0,
            tpPrice:           0,
            lossAmount:        0,
            profitAmount:      0,
            rewardRiskRatio:   0,
            fees,
            quantity,
            orderType:  'market',
            category:   null,
            emotion:    null,
            mistakeType:null,
            comment:    `Imported from Coinbase โ€” ${r[tsIdx] || ''}`,
            status:     'pending'
        });
    }
    return trades;
}

// ---- Interactive Brokers (IBKR) CSV Parser ----
// Format: multi-section CSV
// Header row:  Transaction History,Header,Date,Account,Description,Transaction Type,Symbol,Quantity,Price,Price Currency,Gross Amount,Commission,Net Amount
// Data rows:   Transaction History,Data,2026-02-19,U***03200,DERMATA...,Buy,DRMA,10.0,1.89,USD,-18.9,-0.219,-19.119
//
// Logic: Group multiple Buy/Sell fills by Symbol+Date โ†’ one reconstructed trade per symbol-day
function parseIBKRCSV(text) {
    const lines = text.split(/\r?\n/).filter(l => l.trim().length > 0);

    // Find the Transaction History header row and collect data rows
    let headerCols = null;
    const dataRows = [];

    for (const line of lines) {
        const cols = parseCSVLine(line);
        if (!cols || cols.length < 3) continue;

        const section = (cols[0] || '').trim();
        const rowType = (cols[1] || '').trim();

        if (section === 'Transaction History' && rowType === 'Header') {
            headerCols = cols;
        } else if (section === 'Transaction History' && rowType === 'Data') {
            dataRows.push(cols);
        }
    }

    if (!headerCols || dataRows.length === 0) return [];

    // Build column index lookup (headerCols[0]='Transaction History', [1]='Header', [2]='Date', ...)
    // So the actual header names start at index 2
    const hdrNames = headerCols.slice(2).map(h => h.toLowerCase().trim());
    const col = (...names) => {
        for (const name of names) {
            const i = hdrNames.findIndex(h => h.includes(name));
            if (i >= 0) return i + 2; // +2 because we sliced 2 off
        }
        return -1;
    };

    const dateCol   = col('date');
    const typeCol   = col('transaction type');
    const symbolCol = col('symbol');
    const qtyCol    = col('quantity');
    const priceCol  = col('price');
    const grossCol  = col('gross amount');
    const commCol   = col('commission');
    const netCol    = col('net amount');

    if (symbolCol < 0) return [];

    // Filter to valid trade rows (skip cash transfers where Symbol = '-')
    const tradeRows = dataRows.filter(r => {
        const sym = (r[symbolCol] || '').trim();
        return sym && sym !== '-' && sym !== '' && /^[A-Z0-9.]+$/i.test(sym);
    });

    if (tradeRows.length === 0) return [];

    // Group by Symbol+Date (multiple fills per day = one trade)
    const groups = {};
    for (const r of tradeRows) {
        const symbol = (r[symbolCol] || '').trim().toUpperCase();
        // Date field may include time like "2026-02-19, 10:30" โ€” grab just the date part
        const rawDate = (r[dateCol] || '').trim();
        const date = rawDate.split(',')[0].trim();
        const key = `${symbol}__${date}`;
        if (!groups[key]) groups[key] = { symbol, date, rows: [] };
        groups[key].rows.push(r);
    }

    const trades = [];

    for (const group of Object.values(groups)) {
        const { symbol, date, rows } = group;

        let totalBuyQty    = 0;
        let totalSellQty   = 0;
        let totalBuyGross  = 0; // sum of abs(Gross Amount) for buy fills
        let totalSellGross = 0; // sum of abs(Gross Amount) for sell fills
        let totalFees      = 0; // sum of abs(Commission) for all fills
        let totalNetPnl    = 0; // sum of Net Amount for all fills

        for (const r of rows) {
            const qty   = parseFloat(r[qtyCol])   || 0;
            const gross = parseFloat(r[grossCol]) || 0;
            const comm  = parseFloat(r[commCol])  || 0;
            const net   = parseFloat(r[netCol])   || 0;
            const txType = (r[typeCol] || '').toLowerCase();

            const isBuy  = txType.includes('buy')  || qty > 0;
            const isSell = txType.includes('sell') || qty < 0;

            if (isBuy) {
                totalBuyQty   += Math.abs(qty);
                totalBuyGross += Math.abs(gross);
            }
            if (isSell) {
                totalSellQty   += Math.abs(qty);
                totalSellGross += Math.abs(gross);
            }
            totalFees   += Math.abs(comm);
            totalNetPnl += net;
        }

        // Entry/exit price = weighted average of buy/sell fills
        const entryPrice   = totalBuyQty  > 0 ? totalBuyGross  / totalBuyQty  : 0;
        const exitPrice    = totalSellQty > 0 ? totalSellGross / totalSellQty : 0;
        const positionSize = totalBuyGross;

        // Determine if trade is closed (sell qty โ‰ˆ buy qty, allow 1% rounding tolerance)
        const isClosed = totalSellQty > 0 && (totalSellQty >= totalBuyQty * 0.99);

        let status = 'pending';
        let profitAmount = 0;
        let lossAmount   = 0;

        if (isClosed) {
            if (totalNetPnl > 0.005) {
                status = 'win';
                profitAmount = parseFloat(totalNetPnl.toFixed(2));
            } else if (totalNetPnl < -0.005) {
                status = 'loss';
                lossAmount = parseFloat(Math.abs(totalNetPnl).toFixed(2));
            } else {
                status = 'pending'; // breakeven
            }
        }

        const pnlLabel = isClosed
            ? ` | P&L: ${totalNetPnl >= 0 ? '+' : ''}$${totalNetPnl.toFixed(2)}`
            : ' | Open position';

        trades.push({
            coin:              symbol,
            positionSize:      parseFloat(positionSize.toFixed(2)),
            entryPrice:        parseFloat(entryPrice.toFixed(4)),
            actualExitPrice:   exitPrice > 0 ? parseFloat(exitPrice.toFixed(4)) : 0,
            tradeDate:         date,   // actual IBKR trade date
            stopLossPercent:   0,
            takeProfitPercent: 0,
            slPrice:           0,
            tpPrice:           0,
            lossAmount,
            profitAmount,
            rewardRiskRatio:   0,
            fees:              parseFloat(totalFees.toFixed(4)),
            quantity:          parseFloat(totalBuyQty.toFixed(4)),
            orderType:         'market',
            category:          null,
            emotion:           null,
            mistakeType:       null,
            comment:           `Imported from IBKR โ€” ${date}${pnlLabel}`,
            status,
            _ibkrPnl:          parseFloat(totalNetPnl.toFixed(2)) // used in preview table
        });
    }

    // Sort by date descending
    trades.sort((a, b) => b.tradeDate.localeCompare(a.tradeDate));

    return trades;
}

// ---- IBKR .tlg Parser (Recommended) ----
// Format: pipe-delimited per-execution file used by TraderVue / IBKR export
// STK_TRD|<id>|<symbol>|<name>|<exchange>|<action>|<O/C>|<YYYYMMDD>|<HH:MM:SS>|<currency>|<qty>|<multiplier>|<price>|<value>|<commission>|<mult2>
//   action: BUYTOOPEN | SELLTOCLOSE | BUYTOCOVER | SELLSHORT
//   value:  positive for buys (cost), negative for sells (proceeds)
//   commission: always negative
//
// P&L formula: proceeds_from_sells - cost_of_buys - total_fees
//            = -sum(value) for sells + (-sum(value)) for buys... simplified:
//            = sum( -value - abs(commission) ) for all rows
// ---- IBKR .tlg Parser (Recommended) โ€” UPDATED ----
// Changes:
//   1. Splits multiple round-trips on the same symbol+day into separate trades
//      by tracking open position qty and cutting a new trade whenever it hits 0.
//   2. Calculates exitPricePercent (% gain/loss from entry to exit).
function parseIBKRTLGFile(text) {
    const lines = text.split(/\r?\n/).filter(l => l.trim().startsWith('STK_TRD'));

    // โ”€โ”€ Parse every execution line into a structured row โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    const executions = [];

    for (const line of lines) {
        const f = line.split('|');
        if (f.length < 10) continue;

        // Symbol: first ALL-CAPS alphabetic token (1-6 chars) after f[0]
        let symbol = '';
        for (let fi = 1; fi < f.length; fi++) {
            const v = f[fi].trim();
            if (/^[A-Z]{1,6}$/.test(v) && v !== 'BUY' && v !== 'SELL') { symbol = v; break; }
        }
        if (!symbol) symbol = (f[2] || '').trim().toUpperCase();
        if (!symbol) continue;

        // Action: first field matching BUY/SELL variants
        let action = '';
        for (let fi = 1; fi < f.length; fi++) {
            const v = f[fi].trim().toUpperCase();
            if (/^(BUY|SELL|BUYTOOPEN|BUYTOCOVER|SELLTOCLOSE|SELLSHORT)/.test(v)) { action = v; break; }
        }

        // Date: first 8-digit field looking like 20YYMMDD
        let dateRaw = '';
        for (let fi = 1; fi < f.length; fi++) {
            const v = f[fi].trim();
            if (/^20\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])$/.test(v)) { dateRaw = v; break; }
        }

        // Time: first field matching HH:MM:SS
        let timeStr = '';
        for (let fi = 1; fi < f.length; fi++) {
            const v = f[fi].trim();
            if (/^([01]\d|2[0-3]):[0-5]\d:[0-5]\d$/.test(v)) { timeStr = v; break; }
        }

        const qty   = parseFloat((f[10] || '0').trim()) || 0;
        const price = parseFloat((f[12] || '0').trim()) || 0;
        const value = parseFloat((f[13] || '0').trim()) || 0;
        const comm  = parseFloat((f[14] || '0').trim()) || 0;

        const date = dateRaw.length === 8
            ? `${dateRaw.slice(0, 4)}-${dateRaw.slice(4, 6)}-${dateRaw.slice(6, 8)}`
            : (dateRaw || 'unknown');

        executions.push({ symbol, action, date, time: timeStr, qty, price, value, comm });
    }

    // โ”€โ”€ Sort all executions by symbol, date, time so we can walk them in order โ”€
    executions.sort((a, b) => {
        if (a.symbol !== b.symbol) return a.symbol.localeCompare(b.symbol);
        const da = `${a.date}T${a.time}`;
        const db = `${b.date}T${b.time}`;
        return da.localeCompare(db);
    });

    // โ”€โ”€ Walk executions per symbol, splitting on position-close boundaries โ”€โ”€โ”€โ”€โ”€
    // Group executions by symbol first
    const bySymbol = {};
    for (const ex of executions) {
        if (!bySymbol[ex.symbol]) bySymbol[ex.symbol] = [];
        bySymbol[ex.symbol].push(ex);
    }

    const trades = [];

    for (const [symbol, execs] of Object.entries(bySymbol)) {
        // Walk the executions in time order, accumulating a running net qty.
        // When running qty returns to 0 (or flips sign), that's a complete round-trip โ†’ cut trade.
        let runningQty = 0;
        let currentGroup = [];

        for (const ex of execs) {
            const isBuy  = ex.action === 'BUYTOOPEN'   || ex.action === 'BUYTOCOVER'  || ex.qty > 0;
            const isSell = ex.action === 'SELLTOCLOSE' || ex.action === 'SELLSHORT'   || ex.qty < 0;
            const signedQty = isBuy ? Math.abs(ex.qty) : -Math.abs(ex.qty);

            currentGroup.push(ex);
            runningQty += signedQty;

            // Position fully closed โ€” save this trade and start fresh
            if (Math.abs(runningQty) < 0.001 && currentGroup.length > 0) {
                trades.push(buildTradeFromGroup(symbol, currentGroup));
                currentGroup = [];
                runningQty = 0;
            }
        }

        // Any remaining open executions = open/partial position
        if (currentGroup.length > 0) {
            trades.push(buildTradeFromGroup(symbol, currentGroup));
        }
    }

    // Sort by date descending
    trades.sort((a, b) => {
        const da = `${b.tradeDate}T${b._firstTime || ''}`;
        const db = `${a.tradeDate}T${a._firstTime || ''}`;
        return da.localeCompare(db);
    });

    // Clean up internal field before returning
    trades.forEach(t => { delete t._firstTime; });

    return trades;
}

// โ”€โ”€ Builds a single trade object from a group of execution rows โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
function buildTradeFromGroup(symbol, rows) {
    let totalBuyQty    = 0;
    let totalBuyGross  = 0;
    let totalSellQty   = 0;
    let totalSellGross = 0;
    let totalFees      = 0;
    let totalNetPnl    = 0;

    for (const r of rows) {
        const isBuy  = r.action === 'BUYTOOPEN'   || r.action === 'BUYTOCOVER'  || r.qty > 0;
        const isSell = r.action === 'SELLTOCLOSE' || r.action === 'SELLSHORT'   || r.qty < 0;

        if (isBuy) {
            totalBuyQty   += Math.abs(r.qty);
            totalBuyGross += Math.abs(r.value);
        }
        if (isSell) {
            totalSellQty   += Math.abs(r.qty);
            totalSellGross += Math.abs(r.value);
        }

        totalFees   += Math.abs(r.comm);
        totalNetPnl += -r.value - Math.abs(r.comm);
    }

    const entryPrice   = totalBuyQty  > 0 ? totalBuyGross  / totalBuyQty  : 0;
    const exitPrice    = totalSellQty > 0 ? totalSellGross / totalSellQty : 0;
    const positionSize = totalBuyGross;
    const isClosed     = totalSellQty > 0 && totalSellQty >= totalBuyQty * 0.99;

    // % gain/loss from entry to exit  (positive = profit, negative = loss)
    const exitPricePercent = (isClosed && entryPrice > 0)
        ? parseFloat((((exitPrice - entryPrice) / entryPrice) * 100).toFixed(3))
        : 0;

    let status = 'pending';
    let profitAmount = 0;
    let lossAmount   = 0;

    if (isClosed) {
        if (totalNetPnl > 0.005) {
            status = 'win';
            profitAmount = parseFloat(totalNetPnl.toFixed(2));
        } else if (totalNetPnl < -0.005) {
            status = 'loss';
            lossAmount = parseFloat(Math.abs(totalNetPnl).toFixed(2));
        }
    }

    // Use the date of the first execution in this group
    const tradeDate = rows[0].date;
    const firstTime = rows[0].time || '';

    const pnlLabel = isClosed
        ? ` | P&L: ${totalNetPnl >= 0 ? '+' : ''}$${totalNetPnl.toFixed(2)} (${exitPricePercent >= 0 ? '+' : ''}${exitPricePercent}%)`
        : ' | Open position';

    return {
        coin:              symbol,
        positionSize:      parseFloat(positionSize.toFixed(2)),
        entryPrice:        parseFloat(entryPrice.toFixed(4)),
        actualExitPrice:   exitPrice > 0 ? parseFloat(exitPrice.toFixed(4)) : 0,
        exitPricePercent,                       // โ† NEW: % move from entry to exit
        tradeDate,
        _firstTime:        firstTime,           // used for sorting, deleted before return
        stopLossPercent:   0,
        takeProfitPercent: 0,
        slPrice:           0,
        tpPrice:           0,
        lossAmount,
        profitAmount,
        rewardRiskRatio:   0,
        fees:              parseFloat(totalFees.toFixed(4)),
        quantity:          parseFloat(totalBuyQty.toFixed(4)),
        orderType:         'market',
        category:          null,
        emotion:           null,
        mistakeType:       null,
        comment:           `Imported from IBKR (.tlg) โ€” ${tradeDate}${pnlLabel}`,
        status,
        _ibkrPnl:          parseFloat(totalNetPnl.toFixed(2))
    };
}
// ============================================
// PREVIEW RENDERER
// ============================================

function renderImportPreview() {
    const container = document.getElementById('import-preview');
    if (!container) return;

    const trades = importState.parsedTrades;
    if (trades.length === 0) {
        container.innerHTML = '';
        return;
    }

    container.innerHTML = `
        <div class="glass rounded-3xl p-6 border border-violet-500/20 slide-up">
            <div class="flex items-center gap-2 mb-4">
                <div class="w-6 h-6 rounded-full gradient-bg flex items-center justify-center text-xs font-bold text-white">3</div>
                <h3 class="text-lg font-semibold text-white">Preview โ€” ${trades.length} Trade(s)</h3>
            </div>

            <div class="overflow-x-auto rounded-xl border border-violet-500/20 mb-4">
                <table class="w-full text-sm">
                    <thead>
                        <tr class="bg-violet-500/10 text-violet-300 text-left">
                            <th class="px-4 py-3 font-semibold whitespace-nowrap">Asset</th>
                            ${(importState.format === 'ibkr' || importState.format === 'ibkr-tlg') ? `
                                <th class="px-4 py-3 font-semibold whitespace-nowrap text-amber-300">Trade Date</th>
                            ` : ''}
                            <th class="px-4 py-3 font-semibold whitespace-nowrap">Position</th>
                            <th class="px-4 py-3 font-semibold whitespace-nowrap">Entry</th>
                            ${(importState.format === 'ibkr' || importState.format === 'ibkr-tlg') ? `
                                <th class="px-4 py-3 font-semibold whitespace-nowrap">Exit</th>
                                <th class="px-4 py-3 font-semibold whitespace-nowrap">Qty</th>
                                <th class="px-4 py-3 font-semibold whitespace-nowrap">Fees</th>
                                <th class="px-4 py-3 font-semibold whitespace-nowrap">Net P&L</th>
                            ` : `
                                <th class="px-4 py-3 font-semibold whitespace-nowrap">SL%</th>
                                <th class="px-4 py-3 font-semibold whitespace-nowrap">TP%</th>
                            `}
                            <th class="px-4 py-3 font-semibold whitespace-nowrap">Status</th>
                        </tr>
                    </thead>
                    <tbody class="divide-y divide-violet-500/10">
                        ${trades.slice(0, 25).map(t => `
                            <tr class="text-slate-300 hover:bg-violet-500/5 transition">
                                <td class="px-4 py-2.5 font-semibold text-white">${t.coin || 'โ€”'}</td>
                                ${(importState.format === 'ibkr' || importState.format === 'ibkr-tlg') ? `
                                    <td class="px-4 py-2.5 font-mono text-amber-300 text-xs whitespace-nowrap">${t.tradeDate || 'โš  unknown'}</td>
                                ` : ''}
                                <td class="px-4 py-2.5">${t.positionSize > 0 ? '$' + parseFloat(t.positionSize).toFixed(2) : 'โ€”'}</td>
                                <td class="px-4 py-2.5">${t.entryPrice > 0 ? '$' + parseFloat(t.entryPrice).toFixed(4) : 'โ€”'}</td>
                                ${(importState.format === 'ibkr' || importState.format === 'ibkr-tlg') ? `
                                    <td class="px-4 py-2.5 text-slate-300">${(t.actualExitPrice || 0) > 0 ? '$' + parseFloat(t.actualExitPrice).toFixed(4) : 'โ€”'}</td>
                                    <td class="px-4 py-2.5 text-slate-400">${t.quantity > 0 ? parseFloat(t.quantity).toFixed(2) : 'โ€”'}</td>
                                    <td class="px-4 py-2.5 text-slate-400">${t.fees > 0 ? '$' + parseFloat(t.fees).toFixed(2) : 'โ€”'}</td>
                                    <td class="px-4 py-2.5 font-semibold ${(t._ibkrPnl || 0) >= 0 ? 'text-green-400' : 'text-red-400'}">
                                        ${t._ibkrPnl != null ? ((t._ibkrPnl >= 0 ? '+' : '') + '$' + parseFloat(t._ibkrPnl).toFixed(2)) : 'โ€”'}
                                    </td>
                                ` : `
                                    <td class="px-4 py-2.5 text-red-300">${t.stopLossPercent > 0 ? t.stopLossPercent + '%' : 'โ€”'}</td>
                                    <td class="px-4 py-2.5 text-green-300">${t.takeProfitPercent > 0 ? t.takeProfitPercent + '%' : 'โ€”'}</td>
                                `}
                                <td class="px-4 py-2.5">
                                    <span class="px-2 py-0.5 rounded-full text-xs font-semibold
                                        ${t.status === 'win' ? 'bg-green-500/20 text-green-300'
                                        : t.status === 'loss' ? 'bg-red-500/20 text-red-300'
                                        : 'bg-yellow-500/20 text-yellow-300'}">
                                        ${t.status || 'pending'}
                                    </span>
                                </td>
                            </tr>
                        `).join('')}
                    </tbody>
                </table>
                ${trades.length > 25 ? `<p class="text-center text-xs text-slate-500 py-2">... and ${trades.length - 25} more trades</p>` : ''}
            </div>

            <!-- Notes for exchange imports -->
            ${importState.format !== 'app' ? `
                <div class="bg-yellow-500/10 border border-yellow-500/20 rounded-xl p-4 mb-4 text-sm text-yellow-200">
                    <strong>Note:</strong> Exchange imports create <em>pending</em> trades. SL% and TP% are set to 0 โ€” you can update each trade after import.
                </div>
            ` : ''}

            <!-- Import Button -->
            <button onclick="confirmImport()"
                class="w-full gradient-bg text-white py-4 rounded-2xl font-bold text-lg shadow-lg active:scale-95 transition">
                Import ${trades.length} Trade(s) โ†’
            </button>
        </div>
    `;
}

// ============================================
// CONFIRM & EXECUTE IMPORT
// ============================================

async function confirmImport() {
    const trades = importState.parsedTrades;
    if (trades.length === 0) {
        showToast('No trades to import', 'error');
        return;
    }

    const mode = getTradeMode();
    showToast('Importing...', 'info');

    const result = await apiPost('bulkImportTrades', { trades, mode });

    if (result.success) {
        const msg = result.errors && result.errors.length > 0
            ? `Imported ${result.imported} trade(s). ${result.errors.length} row(s) had errors.`
            : `Successfully imported ${result.imported} trade(s)!`;
        showToast(msg, 'success');

        // Reset import state
        importState.parsedTrades = [];
        importState.fileName = null;
        importState.rawText = '';

        // Navigate to trades list
        setTimeout(() => navigateTo('history'), 1200);
    } else {
        showToast('Import failed. Please check your file format.', 'error');
    }
}

// ============================================
// GLOBAL EXPORTS
// ============================================
window.renderImport       = renderImport;
window.selectImportFormat = selectImportFormat;
window.handleImportFile   = handleImportFile;
window.renderImportPreview = renderImportPreview;
window.confirmImport      = confirmImport;
window.importState        = importState;