"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.onOrderCreated = onOrderCreated;
exports.onOrderClosed = onOrderClosed;
exports.onFollowerOrderClosed = onFollowerOrderClosed;
const db_1 = require("@b/db");
const cron_1 = require("./cron");
const wallet_1 = require("@b/api/(ext)/ecosystem/utils/wallet");
const index_1 = require("./index");
const console_1 = require("@b/utils/console");
const stats_calculator_1 = require("./stats-calculator");
/**
 * Hook to be called when a user places an order in the ecosystem
 * Checks if user is a leader and creates a copy trade for replication
 */
async function onOrderCreated(order) {
    try {
        // Check if user is an active leader
        const leader = await db_1.models.copyTradingLeader.findOne({
            where: {
                userId: order.userId,
                status: "ACTIVE",
            },
        });
        if (!leader) {
            return; // User is not a leader, no action needed
        }
        const leaderData = leader;
        // Check if leader is trading on a declared market
        const leaderMarket = await db_1.models.copyTradingLeaderMarket.findOne({
            where: {
                leaderId: leaderData.id,
                symbol: order.symbol,
                isActive: true,
            },
        });
        if (!leaderMarket) {
            console_1.logger.warn("COPY_TRADING", `Leader ${leaderData.id} trading on undeclared market ${order.symbol} - skipping copy`);
            return; // Leader is trading on an undeclared market, don't copy
        }
        // Check if leader has any active followers
        const activeFollowers = await db_1.models.copyTradingFollower.count({
            where: {
                leaderId: leaderData.id,
                status: "ACTIVE",
            },
        });
        if (activeFollowers === 0) {
            return; // No followers to replicate to
        }
        // Create leader trade record for replication
        const leaderTrade = await db_1.models.copyTradingTrade.create({
            leaderId: leaderData.id,
            symbol: order.symbol,
            side: order.side,
            type: order.type,
            amount: order.amount,
            price: order.price,
            cost: order.side === "BUY" ? order.amount * order.price : order.amount,
            status: "PENDING_REPLICATION",
            orderId: order.id,
        });
        // Get leader's balance for proportional calculations
        const [, pair] = order.symbol.split("/");
        const leaderWallet = await (0, wallet_1.getWalletByUserIdAndCurrency)(order.userId, pair);
        const leaderBalance = leaderWallet ? parseFloat(leaderWallet.balance.toString()) : 0;
        // Trigger immediate replication (async - don't wait)
        (0, cron_1.replicateLeaderTrade)({
            id: leaderTrade.id,
            leaderId: leaderData.id,
            symbol: order.symbol,
            side: order.side,
            type: order.type,
            amount: order.amount,
            price: order.price,
            status: "PENDING_REPLICATION",
            createdAt: new Date(),
        }, leaderBalance).catch((error) => {
            console_1.logger.error("COPY_TRADING", "Failed to replicate leader trade", error);
        });
        // Create audit log
        await (0, index_1.createAuditLog)({
            userId: order.userId,
            action: "TRADE_OPEN",
            entityType: "copyTradingTrade",
            entityId: leaderTrade.id,
            metadata: {
                symbol: order.symbol,
                side: order.side,
                amount: order.amount,
                price: order.price,
                followers: activeFollowers,
            },
        });
    }
    catch (error) {
        console_1.logger.error("COPY_TRADING", "Error in onOrderCreated hook", error);
        // Don't throw - we don't want to fail the order creation
    }
}
/**
 * Hook to be called when an order is filled/closed
 * Updates copy trades and triggers profit distribution
 */
async function onOrderClosed(orderId, profit, closedAt) {
    try {
        // Find the leader trade associated with this order
        const leaderTrade = await db_1.models.copyTradingTrade.findOne({
            where: {
                orderId,
                followerId: null, // Leader trade
            },
        });
        if (!leaderTrade) {
            return; // Not a copy trading leader's trade
        }
        const trade = leaderTrade;
        // Update leader trade
        await trade.update({
            profit,
            profitPercent: trade.cost > 0 ? (profit / trade.cost) * 100 : 0,
            status: "CLOSED",
            closedAt,
        });
        // Find all follower trades that copied this
        const followerTrades = await db_1.models.copyTradingTrade.findAll({
            where: {
                leaderTradeId: trade.id,
                status: { [db_1.models.Sequelize.Op.ne]: "CLOSED" },
            },
        });
        // Mark follower trades as closed (profit will be calculated when their orders close)
        for (const followerTrade of followerTrades) {
            // Note: Actual profit for follower is calculated when their order closes
            // This just marks them for processing
            await followerTrade.update({
                status: "PENDING_CLOSE",
                closedProfit: profit, // Reference profit from leader
            });
        }
        // Invalidate leader stats cache (stats are calculated on-demand)
        await (0, stats_calculator_1.invalidateLeaderStatsCache)(trade.leaderId);
        // Create audit log
        await (0, index_1.createAuditLog)({
            userId: trade.leaderId,
            action: "TRADE_CLOSE",
            entityType: "copyTradingTrade",
            entityId: trade.id,
            metadata: {
                profit,
                followerTrades: followerTrades.length,
            },
        });
    }
    catch (error) {
        console_1.logger.error("COPY_TRADING", "Error in onOrderClosed hook", error);
    }
}
/**
 * Hook to be called when a follower's copied order is closed
 */
async function onFollowerOrderClosed(orderId, profit, closedAt) {
    try {
        // Find the follower trade associated with this order
        const followerTrade = await db_1.models.copyTradingTrade.findOne({
            where: {
                orderId,
                followerId: { [db_1.models.Sequelize.Op.ne]: null },
            },
            include: [
                {
                    model: db_1.models.copyTradingFollower,
                    as: "follower",
                    include: [{ model: db_1.models.copyTradingLeader, as: "leader" }],
                },
            ],
        });
        if (!followerTrade) {
            return; // Not a copy trade
        }
        const trade = followerTrade;
        const follower = trade.follower;
        const leader = follower === null || follower === void 0 ? void 0 : follower.leader;
        // Update trade with actual profit
        await trade.update({
            profit,
            profitPercent: trade.cost > 0 ? (profit / trade.cost) * 100 : 0,
            status: "CLOSED",
            closedAt,
            closedProfit: profit,
        });
        // Calculate and distribute profit shares
        if (profit > 0 && leader) {
            const platformFeePercent = 2;
            const leaderSharePercent = leader.profitSharePercent || 20;
            const platformFee = profit * (platformFeePercent / 100);
            const leaderProfit = (profit - platformFee) * (leaderSharePercent / 100);
            // Use transaction to prevent race condition on wallet balance
            await db_1.sequelize.transaction(async (t) => {
                // Currency for profit share is determined from the trade
                const profitCurrency = trade.profitCurrency || "USDT";
                // Create profit share transaction records
                await db_1.models.copyTradingTransaction.create({
                    followerId: follower.id,
                    type: "PROFIT_SHARE",
                    amount: leaderProfit,
                    currency: profitCurrency,
                    description: `Leader profit share for trade ${trade.id}`,
                    metadata: { tradeId: trade.id, leaderId: leader.id },
                }, { transaction: t });
                await db_1.models.copyTradingTransaction.create({
                    followerId: follower.id,
                    type: "PLATFORM_FEE",
                    amount: platformFee,
                    currency: profitCurrency,
                    description: `Platform fee for trade ${trade.id}`,
                    metadata: { tradeId: trade.id },
                }, { transaction: t });
                // Credit leader's wallet with proper locking
                const leaderWallet = await (0, wallet_1.getWalletByUserIdAndCurrency)(leader.userId, profitCurrency);
                if (leaderWallet) {
                    await (0, wallet_1.updateWalletBalance)(leaderWallet, leaderProfit, "add", `ct_leader_profit_${trade.id}`, t);
                }
            });
        }
        // Update allocation's used amounts when trade closes
        const allocation = await db_1.models.copyTradingFollowerAllocation.findOne({
            where: {
                followerId: follower.id,
                symbol: trade.symbol,
                isActive: true,
            },
        });
        if (allocation) {
            const allocData = allocation;
            if (trade.side === "BUY") {
                // BUY used quote currency - release it
                await allocation.update({
                    quoteUsedAmount: Math.max(0, allocData.quoteUsedAmount - trade.cost),
                });
            }
            else {
                // SELL used base currency - release it
                await allocation.update({
                    baseUsedAmount: Math.max(0, allocData.baseUsedAmount - trade.amount),
                });
            }
            // Invalidate allocation stats cache
            await (0, stats_calculator_1.invalidateAllocationStatsCache)(follower.id, trade.symbol);
        }
        // Invalidate follower stats cache (stats are calculated on-demand)
        await (0, stats_calculator_1.invalidateFollowerStatsCache)(follower.id);
    }
    catch (error) {
        console_1.logger.error("COPY_TRADING", "Error in onFollowerOrderClosed hook", error);
    }
}
