import { createClient } from '@supabase/supabase-js';
import { config } from '../config/index.js';

type OrderRow = {
    profile_id?: string | null;
    user_id?: string | null;
    symbol?: string | null;
    trade_id?: string | null;
    action?: string | null;
    qty?: number | string | null;
    status?: string | null;
    created_at?: string | null;
};

type HistoryRow = {
    profile_id?: string | null;
    user_id?: string | null;
    symbol?: string | null;
    trade_id?: string | null;
    size?: number | string | null;
    created_at?: string | null;
};

type TradeKey = string;

type TradeAggregate = {
    profileId: string;
    userId: string;
    symbol: string;
    tradeId: string;
    entryQty: number;
    exitQty: number;
    orderCount: number;
    hasHistory: boolean;
    historyRows: number;
};

function parseArg(name: string): string | undefined {
    const index = process.argv.findIndex((arg) => arg === `--${name}`);
    if (index < 0) return undefined;
    return process.argv[index + 1];
}

function normalizeNumber(raw: unknown): number {
    const value = Number(raw);
    return Number.isFinite(value) ? value : 0;
}

function normalizeKeyToken(raw: string | null | undefined, fallback: string): string {
    const value = String(raw || '').trim();
    return value || fallback;
}

function toTradeKey(profileId: string, tradeId: string): TradeKey {
    return `${profileId}::${tradeId}`;
}

async function main() {
    if (!config.SUPABASE_URL || !config.SUPABASE_KEY) {
        throw new Error('SUPABASE_URL / SUPABASE_KEY must be configured');
    }

    const sinceDays = Number(parseArg('days') || '14');
    const since = new Date(Date.now() - Math.max(1, sinceDays) * 24 * 60 * 60 * 1000).toISOString();
    const outPath = parseArg('out');

    const supabase = createClient(config.SUPABASE_URL, config.SUPABASE_KEY);

    const { data: orders, error: orderError } = await supabase
        .from('orders')
        .select('profile_id,user_id,symbol,trade_id,action,qty,status,created_at')
        .in('status', ['filled', 'partially_filled'])
        .gte('created_at', since)
        .order('created_at', { ascending: true })
        .limit(10000);
    if (orderError) {
        throw new Error(`Failed to fetch orders: ${orderError.message}`);
    }

    const { data: history, error: historyError } = await supabase
        .from('trade_history')
        .select('profile_id,user_id,symbol,trade_id,size,created_at')
        .gte('created_at', since)
        .order('created_at', { ascending: true })
        .limit(10000);
    if (historyError) {
        throw new Error(`Failed to fetch trade_history: ${historyError.message}`);
    }

    const orderRows = (orders || []) as OrderRow[];
    const historyRows = (history || []) as HistoryRow[];

    const missingTradeIdOrders = orderRows.filter((row) => !String(row.trade_id || '').trim());
    const missingTradeIdHistory = historyRows.filter((row) => !String(row.trade_id || '').trim());

    const aggregates = new Map<TradeKey, TradeAggregate>();
    const ensureAggregate = (profileId: string, userId: string, symbol: string, tradeId: string): TradeAggregate => {
        const key = toTradeKey(profileId, tradeId);
        let aggregate = aggregates.get(key);
        if (!aggregate) {
            aggregate = {
                profileId,
                userId,
                symbol,
                tradeId,
                entryQty: 0,
                exitQty: 0,
                orderCount: 0,
                hasHistory: false,
                historyRows: 0
            };
            aggregates.set(key, aggregate);
        }
        return aggregate;
    };

    for (const row of orderRows) {
        const tradeId = String(row.trade_id || '').trim();
        if (!tradeId) continue;

        const profileId = normalizeKeyToken(row.profile_id, normalizeKeyToken(row.user_id, 'global'));
        const userId = normalizeKeyToken(row.user_id, 'global');
        const symbol = normalizeKeyToken(row.symbol, 'UNKNOWN');
        const action = String(row.action || '').trim().toUpperCase();
        const qty = Math.abs(normalizeNumber(row.qty));

        const aggregate = ensureAggregate(profileId, userId, symbol, tradeId);
        aggregate.orderCount += 1;
        if (action === 'ENTRY') {
            aggregate.entryQty += qty;
        } else if (action === 'EXIT') {
            aggregate.exitQty += qty;
        }
    }

    const historyOnlyTradeKeys: string[] = [];
    for (const row of historyRows) {
        const tradeId = String(row.trade_id || '').trim();
        if (!tradeId) continue;

        const profileId = normalizeKeyToken(row.profile_id, normalizeKeyToken(row.user_id, 'global'));
        const userId = normalizeKeyToken(row.user_id, 'global');
        const symbol = normalizeKeyToken(row.symbol, 'UNKNOWN');
        const key = toTradeKey(profileId, tradeId);

        const aggregate = aggregates.get(key);
        if (!aggregate) {
            historyOnlyTradeKeys.push(key);
            continue;
        }

        aggregate.hasHistory = true;
        aggregate.historyRows += 1;
        aggregate.userId = userId;
        aggregate.symbol = symbol;
    }

    const exitExceedsEntry: TradeAggregate[] = [];
    const closedWithoutHistory: TradeAggregate[] = [];
    const openWithoutHistory: TradeAggregate[] = [];

    for (const aggregate of aggregates.values()) {
        const netQty = aggregate.entryQty - aggregate.exitQty;
        if (netQty < -1e-8) {
            exitExceedsEntry.push(aggregate);
            continue;
        }

        if (!aggregate.hasHistory && netQty <= 1e-8) {
            closedWithoutHistory.push(aggregate);
            continue;
        }

        if (!aggregate.hasHistory && netQty > 1e-8) {
            openWithoutHistory.push(aggregate);
        }
    }

    const report = {
        generatedAt: new Date().toISOString(),
        since,
        totals: {
            orders: orderRows.length,
            history: historyRows.length,
            tradesTracked: aggregates.size
        },
        anomalies: {
            missingTradeIdOrders: missingTradeIdOrders.length,
            missingTradeIdHistory: missingTradeIdHistory.length,
            exitExceedsEntry: exitExceedsEntry.length,
            closedWithoutHistory: closedWithoutHistory.length,
            openWithoutHistory: openWithoutHistory.length,
            historyWithoutOrders: historyOnlyTradeKeys.length
        },
        samples: {
            exitExceedsEntry: exitExceedsEntry.slice(0, 20),
            closedWithoutHistory: closedWithoutHistory.slice(0, 20),
            openWithoutHistory: openWithoutHistory.slice(0, 20),
            historyWithoutOrders: historyOnlyTradeKeys.slice(0, 20)
        }
    };

    const reportJson = JSON.stringify(report, null, 2);
    if (outPath) {
        const fs = await import('node:fs/promises');
        await fs.writeFile(outPath, reportJson, 'utf8');
        console.log(`[LifecycleReconcile] Report written to ${outPath}`);
    } else {
        console.log(reportJson);
    }
}

main().catch((error) => {
    console.error('[LifecycleReconcile] Failed:', error);
    process.exit(1);
});
