export interface RuntimePositionSnapshot {
    id: string;
    symbol: string;
    side: 'BUY' | 'SELL';
    size: number;
    entryPrice: number;
    currentPrice: number;
    stopLoss: number;
    takeProfit: number;
    unrealizedPnl: number;
    unrealizedPnlPercent: number;
    marketValue: number;
    userId?: string;
    profileId?: string;
    profileName?: string;
    tradeId?: string;
}

export interface RuntimeOrderSnapshot {
    id: string;
    symbol: string;
    type: string;
    side: string;
    qty: number;
    price: number;
    status: string;
    timestamp: number;
    userId?: string;
    profileId?: string;
    trade_id?: string;
    subTag?: string;
    action?: string;
    source?: 'BOT' | 'MANUAL';
    created_at?: string;
}

const STABLE_SYNC_SUFFIX = '-SYNC';

const normalizeTradeId = (value?: string): string => String(value || '').trim();

const hasStableTradeId = (tradeId?: string): boolean => {
    const normalized = normalizeTradeId(tradeId);
    return normalized.length > 0 && !normalized.endsWith(STABLE_SYNC_SUFFIX);
};

const toTimestamp = (value: number | string | undefined, createdAt?: string): number => {
    if (typeof value === 'number' && Number.isFinite(value)) return value;
    if (typeof value === 'string') {
        const numeric = Number(value);
        if (Number.isFinite(numeric) && numeric > 0) return numeric;
        const parsed = Date.parse(value);
        if (Number.isFinite(parsed) && parsed > 0) return parsed;
    }
    if (createdAt) {
        const parsedCreatedAt = Date.parse(createdAt);
        if (Number.isFinite(parsedCreatedAt) && parsedCreatedAt > 0) return parsedCreatedAt;
    }
    return 0;
};

const toNumber = (value: unknown): number => {
    const numeric = Number(value);
    return Number.isFinite(numeric) ? numeric : 0;
};

const positive = (value: unknown): number => {
    const numeric = toNumber(value);
    return numeric > 0 ? numeric : 0;
};

const positionScore = (position: RuntimePositionSnapshot): number => {
    const tradeScore = hasStableTradeId(position.tradeId) ? 4 : (normalizeTradeId(position.tradeId) ? 2 : 0);
    const profileScore = position.profileId ? 3 : 0;
    const userScore = position.userId ? 2 : 0;
    const namedScore = position.profileName ? 1 : 0;
    const priceScore = positive(position.currentPrice) > 0 ? 1 : 0;
    const notionalScore = positive(position.entryPrice) * positive(position.size);
    return tradeScore + profileScore + userScore + namedScore + priceScore + Math.min(notionalScore, 100_000);
};

const mergePosition = (
    left: RuntimePositionSnapshot,
    right: RuntimePositionSnapshot
): RuntimePositionSnapshot => {
    const leftScore = positionScore(left);
    const rightScore = positionScore(right);
    const preferred = rightScore >= leftScore ? right : left;
    const fallback = preferred === right ? left : right;

    return {
        ...fallback,
        ...preferred,
        id: preferred.id || fallback.id,
        symbol: preferred.symbol || fallback.symbol,
        side: preferred.side || fallback.side,
        size: positive(preferred.size) > 0 ? preferred.size : fallback.size,
        entryPrice: positive(preferred.entryPrice) > 0 ? preferred.entryPrice : fallback.entryPrice,
        currentPrice: positive(preferred.currentPrice) > 0 ? preferred.currentPrice : fallback.currentPrice,
        stopLoss: positive(preferred.stopLoss) > 0 ? preferred.stopLoss : fallback.stopLoss,
        takeProfit: positive(preferred.takeProfit) > 0 ? preferred.takeProfit : fallback.takeProfit,
        marketValue: positive(preferred.marketValue) > 0 ? preferred.marketValue : fallback.marketValue,
        profileId: preferred.profileId || fallback.profileId,
        userId: preferred.userId || fallback.userId,
        profileName: preferred.profileName || fallback.profileName,
        tradeId: normalizeTradeId(preferred.tradeId) || normalizeTradeId(fallback.tradeId) || undefined
    };
};

const fallbackPositionKey = (position: RuntimePositionSnapshot): string => {
    const owner = `${position.userId || 'global'}:${position.profileId || 'global'}`;
    return `${owner}:${position.symbol}:${position.side}`;
};

const orderStatusRank = (status?: string): number => {
    const normalized = String(status || '').trim().toLowerCase();
    if (normalized === 'filled') return 6;
    if (normalized === 'partially_filled' || normalized === 'partially-filled') return 5;
    if (normalized === 'canceled' || normalized === 'cancelled' || normalized === 'rejected' || normalized === 'expired') return 4;
    if (normalized === 'pending_new' || normalized === 'pending' || normalized === 'accepted' || normalized === 'new') return 2;
    if (normalized === 'unknown') return 1;
    return 2;
};

const pickReliableStatus = (left: RuntimeOrderSnapshot, right: RuntimeOrderSnapshot): string => {
    const leftStatus = String(left.status || '').trim().toLowerCase() || 'unknown';
    const rightStatus = String(right.status || '').trim().toLowerCase() || 'unknown';
    const leftRank = orderStatusRank(leftStatus);
    const rightRank = orderStatusRank(rightStatus);
    if (leftRank !== rightRank) {
        return rightRank > leftRank ? rightStatus : leftStatus;
    }
    const leftTs = toTimestamp(left.timestamp, left.created_at);
    const rightTs = toTimestamp(right.timestamp, right.created_at);
    return rightTs >= leftTs ? rightStatus : leftStatus;
};

const normalizeOrderSource = (order: RuntimeOrderSnapshot): 'BOT' | 'MANUAL' => {
    const normalized = String(order.source || '').trim().toUpperCase();
    if (normalized === 'BOT' || normalized === 'MANUAL') return normalized;
    return order.profileId ? 'BOT' : 'MANUAL';
};

const orderScore = (order: RuntimeOrderSnapshot): number => {
    const profileScore = order.profileId ? 2 : 0;
    const userScore = order.userId ? 1 : 0;
    const tradeScore = normalizeTradeId(order.trade_id) ? 2 : 0;
    const actionScore = order.action ? 1 : 0;
    const statusScore = orderStatusRank(order.status);
    return profileScore + userScore + tradeScore + actionScore + statusScore;
};

const mergeOrder = (
    left: RuntimeOrderSnapshot,
    right: RuntimeOrderSnapshot
): RuntimeOrderSnapshot => {
    const leftScore = orderScore(left);
    const rightScore = orderScore(right);
    const preferred = rightScore >= leftScore ? right : left;
    const fallback = preferred === right ? left : right;
    const preferredTs = toTimestamp(preferred.timestamp, preferred.created_at);
    const fallbackTs = toTimestamp(fallback.timestamp, fallback.created_at);

    return {
        ...fallback,
        ...preferred,
        id: preferred.id || fallback.id,
        symbol: preferred.symbol || fallback.symbol,
        type: preferred.type || fallback.type,
        side: preferred.side || fallback.side,
        qty: positive(preferred.qty) > 0 ? preferred.qty : fallback.qty,
        price: positive(preferred.price) > 0 ? preferred.price : fallback.price,
        timestamp: Math.max(preferredTs, fallbackTs),
        status: pickReliableStatus(left, right),
        userId: preferred.userId || fallback.userId,
        profileId: preferred.profileId || fallback.profileId,
        trade_id: normalizeTradeId(preferred.trade_id) || normalizeTradeId(fallback.trade_id) || undefined,
        subTag: preferred.subTag || fallback.subTag,
        action: preferred.action || fallback.action,
        source: normalizeOrderSource({
            ...fallback,
            ...preferred,
            profileId: preferred.profileId || fallback.profileId
        })
    };
};

export const mergePositionSnapshots = (
    snapshotsBySource: RuntimePositionSnapshot[][]
): RuntimePositionSnapshot[] => {
    const mergedByKey = new Map<string, RuntimePositionSnapshot>();
    for (const position of snapshotsBySource.flat()) {
        const tradeId = normalizeTradeId(position.tradeId);
        const key = hasStableTradeId(tradeId)
            ? `trade:${tradeId}`
            : `fallback:${fallbackPositionKey(position)}`;
        const existing = mergedByKey.get(key);
        if (!existing) {
            mergedByKey.set(key, { ...position, tradeId: tradeId || undefined });
            continue;
        }
        mergedByKey.set(key, mergePosition(existing, { ...position, tradeId: tradeId || undefined }));
    }

    const groupedByOwnerSymbol = new Map<string, RuntimePositionSnapshot[]>();
    for (const position of mergedByKey.values()) {
        const groupKey = fallbackPositionKey(position);
        const group = groupedByOwnerSymbol.get(groupKey) || [];
        group.push(position);
        groupedByOwnerSymbol.set(groupKey, group);
    }

    const output: RuntimePositionSnapshot[] = [];
    for (const group of groupedByOwnerSymbol.values()) {
        const stable = group.filter((position) => hasStableTradeId(position.tradeId));
        if (stable.length > 0) {
            output.push(...stable);
            continue;
        }

        const reduced = group.reduce((acc, current) => (acc ? mergePosition(acc, current) : current), undefined as RuntimePositionSnapshot | undefined);
        if (reduced) output.push(reduced);
    }

    return output.sort((a, b) => {
        const profileCompare = String(a.profileId || '').localeCompare(String(b.profileId || ''));
        if (profileCompare !== 0) return profileCompare;
        const symbolCompare = String(a.symbol || '').localeCompare(String(b.symbol || ''));
        if (symbolCompare !== 0) return symbolCompare;
        return String(a.tradeId || a.id).localeCompare(String(b.tradeId || b.id));
    });
};

export const mergeOrderSnapshots = (
    snapshotsBySource: RuntimeOrderSnapshot[][]
): RuntimeOrderSnapshot[] => {
    const mergedByOrderId = new Map<string, RuntimeOrderSnapshot>();

    for (const order of snapshotsBySource.flat()) {
        const orderId = String(order.id || '').trim();
        if (!orderId) continue;

        const normalizedOrder: RuntimeOrderSnapshot = {
            ...order,
            id: orderId,
            userId: order.userId || undefined,
            profileId: order.profileId || undefined,
            trade_id: normalizeTradeId(order.trade_id) || undefined,
            subTag: String((order as any).subTag || (order as any).subtag || (order as any).sub_tag || '').trim() || undefined,
            status: String(order.status || 'unknown').toLowerCase(),
            timestamp: toTimestamp(order.timestamp, order.created_at),
            source: normalizeOrderSource(order)
        };

        const existing = mergedByOrderId.get(orderId);
        if (!existing) {
            mergedByOrderId.set(orderId, normalizedOrder);
            continue;
        }

        mergedByOrderId.set(orderId, mergeOrder(existing, normalizedOrder));
    }

    return Array.from(mergedByOrderId.values()).sort((a, b) => {
        const tsDiff = toTimestamp(b.timestamp, b.created_at) - toTimestamp(a.timestamp, a.created_at);
        if (tsDiff !== 0) return tsDiff;
        return String(a.id || '').localeCompare(String(b.id || ''));
    });
};
