// src/services/forexService.js
const { Op } = require("sequelize");
const { MarketPair, UserBalance, Asset, DerivativeAccount, sequelize, DerivativeTrade, DerivativePosition, DerivativeOrder, SymbolStats, User, Transaction } = require("../models");
const { NotFoundError, ValidationError, BadRequestError } = require("../utils/errors");
const { baseUrl, getUploadedFile } = require("../utils/helpers");

const forexData = require("../services/forexMarketData");

const CONTRACT_SIZE = 100000;

function toNum(value, fallback = 0) {
    const n = Number(value);
    return Number.isFinite(n) ? n : fallback;
}

function round12(value) {
    return Number(toNum(value).toFixed(12));
}

function mapSide(side) {
    if (side === "buy") return "long";
    if (side === "sell") return "short";
    if (side === "long") return "long";
    if (side === "short") return "short";
    throw new Error("Invalid trade side");
}

function validatePayload(payload) {
    const asset = String(payload.asset || "").trim();
    const side = String(payload.side || "").trim();
    const marketType = String(payload.marketType || "").trim();

    const leverage = toNum(payload.leverage, 0);
    const lot = toNum(payload.lot, 0);
    const limit = payload.limit === "" || payload.limit == null ? null : toNum(payload.limit, 0);
    const stopLoss = payload.stopLoss === "" || payload.stopLoss == null ? null : toNum(payload.stopLoss, 0);
    const takeProfit = payload.takeProfit === "" || payload.takeProfit == null ? null : toNum(payload.takeProfit, 0);

    if (!asset) throw new Error("Asset is required");
    if (!["buy", "sell", "long", "short"].includes(side)) throw new Error("Invalid side");
    if (!["market", "limit", "stop"].includes(marketType)) throw new Error("Invalid market type");
    if (lot <= 0) throw new Error("Lot must be greater than 0");
    if (leverage <= 0) throw new Error("Leverage must be greater than 0");

    if ((marketType === "limit" || marketType === "stop") && (!limit || limit <= 0)) {
        throw new Error(`${marketType} price is required`);
    }

    return {
        asset,
        side,
        marketType,
        leverage,
        lot,
        limit,
        stopLoss,
        takeProfit,
    };
}

function getExecutionPrice({ dbSide, marketType, market, limit }) {

    const bid = toNum(market?.bid ?? market?.sell ?? market?.price, 0);
    const ask = toNum(market?.ask ?? market?.buy ?? market?.price, 0);
    const mid = toNum(market?.price ?? (bid + ask) / 2, 0);

    if (marketType === "market") {
        return dbSide === "long" ? (ask || mid) : (bid || mid);
    }

    return toNum(limit, mid);
}

function computeQtyFromLot(lot) {
    return round12(lot * CONTRACT_SIZE);
}

function computeRequiredMargin({ qty, price, leverage }) {
    return round12((qty * price) / leverage);
}

function computeMarginFields({ balance, unrealizedPnl = 0, marginUsed }) {
    const equity = round12(balance + unrealizedPnl);
    const margin_free = round12(equity - marginUsed);
    const margin_level =
        marginUsed > 0 ? round12((equity / marginUsed) * 100) : 0;

    return {
        equity,
        margin_free,
        margin_level,
    };
}

function validateStops({ dbSide, executionPrice, stopLoss, takeProfit }) {
    if (dbSide === "long") {
        if (stopLoss != null && stopLoss > 0 && stopLoss >= executionPrice) {
            throw new Error("For long positions, stop loss must be below entry price");
        }
        if (takeProfit != null && takeProfit > 0 && takeProfit <= executionPrice) {
            throw new Error("For long positions, take profit must be above entry price");
        }
    }

    if (dbSide === "short") {
        if (stopLoss != null && stopLoss > 0 && stopLoss <= executionPrice) {
            throw new Error("For short positions, stop loss must be above entry price");
        }
        if (takeProfit != null && takeProfit > 0 && takeProfit >= executionPrice) {
            throw new Error("For short positions, take profit must be below entry price");
        }
    }
}



class ForexService {
    /**
     * List forex CFD pairs
     */

    async getPairs(userId) {
        const [
            pairs,
            balance,
            account,
            positions
        ] = await Promise.all([
            MarketPair.findAll({
                where: { type: "fx" },
                include: [
                    { model: Asset, as: 'base' },
                    { model: Asset, as: 'quote' },
                    { model: SymbolStats, as: 'rate' }
                ]
            }),
            UserBalance.findOne({
                where: { userId }
            }),
            DerivativeAccount.findOne({
                where: { user_id: userId }
            }),
            DerivativePosition.findAll({
                where: { userId, status: 'open' },
                order: [['opened_at', 'desc']],
                include: [
                    {
                        model: MarketPair, as: 'pair', include: [
                            { model: Asset, as: 'base' },
                            { model: Asset, as: 'quote' },
                            { model: SymbolStats, as: 'rate' }
                        ]
                    }
                ],
                limit: 5
            })

        ])

        return {
            pairs: pairs.map(p => {
                const baseAsset = p?.base ?? '';
                const quoteAsset = p?.quote ?? '';

                if (!baseAsset && !quoteAsset) return

                return {
                    pair: p.name,
                    symbol: p.symbol,
                    base: baseAsset.symbol,
                    quote: quoteAsset.symbol,
                    price: p.rate?.current_price,
                    high24h: p.rate?.high24h,
                    low24h: p.rate?.low24h,
                    volume24h: p.rate?.volume24h,
                    decimals: p.decimals,
                    precision: p.pricePrecision,
                    baseLogo: getUploadedFile(baseAsset?.logo, 'assets'),
                    quoteLogo: getUploadedFile(quoteAsset?.logo, 'assets'),
                }
            }).filter(Boolean),
            positions: positions.map(t => {
                const baseAsset = t.pair?.base ?? '';
                const quoteAsset = t.pair?.quote ?? '';
                const price = t.pair?.rate ?? {};
                if (!baseAsset && !quoteAsset) return

                return {
                    id: t.id,
                    symbol: t.pair?.symbol,
                    baseSymbol: baseAsset?.symbol || "—",
                    quoteSymbol: quoteAsset?.symbol || "—",
                    baselogo: getUploadedFile(baseAsset?.logo, 'assets') || null,
                    quotelogo: getUploadedFile(quoteAsset?.logo, 'assets') || null,
                    type: t.side,
                    entryPrice: t.entry_price,
                    price: price?.price,
                    low24h: price?.low24h,
                    high24: price?.high24h,
                    leverage: t.leverage,
                    lots: t.qty || 0,
                    sl: t.stop_loss ?? '-',
                    tp: t.take_profit ?? '-',
                    status: t.status.charAt(0).toUpperCase() + t.status.slice(1),
                    time: new Date(t.opened_at).toISOString().replace('T', ' ').substring(0, 19)
                }
            }).filter(Boolean),
            account: {
                balance: account.balance,
                equity: account.equity,
                free: account.margin_free,
                used: account.margin_used,
                level: account.margin_level
            },
            balance: balance ? Number(balance?.trading) : 0
        }
    };

    async getOrCreateDerivativeAccount({ userId, transaction }) {
        let account = await DerivativeAccount.findOne({
            where: {
                user_id: userId,
                kind: "forex_cfd",
            },
            transaction,
            lock: transaction.LOCK.UPDATE,
        });

        if (!account) {
            account = await DerivativeAccount.create(
                {
                    user_id: userId,
                    kind: "forex_cfd",
                    margin_mode: "cross",
                    equity: 0,
                    balance: 0,
                    margin_used: 0,
                    margin_free: 0,
                    margin_level: 0,
                    status: "active",
                },
                { transaction }
            );
        }

        return account;
    }

    async getMarketBySymbol({ asset, transaction }) {
        // replace this with your own market lookup if needed
        const market = await MarketPair.findOne({
            where: {

                symbol: asset


            },
            transaction,
        });

        if (!market) {
            throw new Error(`Market ${asset} not found`);
        }

        return market;
    }


    async createPendingOrder({
        userId,
        account,
        market,
        dbSide,
        marketType,
        leverage,
        qty,
        triggerPrice,
        transaction,
    }) {
        const order = await DerivativeOrder.create(
            {
                userId,
                account_id: account.id,
                market_id: market.id,
                side: dbSide,
                type: marketType,
                price: marketType === "limit" ? triggerPrice : null,
                trigger_price: marketType === "stop" ? triggerPrice : null,
                qty,
                qty_filled: 0,
                leverage,
                reduce_only: false,
                status: "new",
            },
            { transaction }
        );

        return order;
    }

    async fillMarketOrderAndOpenPosition({
        userId,
        account,
        market,
        dbSide,
        marketType,
        leverage,
        qty,
        executionPrice,
        stopLoss,
        takeProfit,
        transaction,
    }) {

        const order = await DerivativeOrder.create(
            {
                account_id: account.id,
                market_id: market.id,
                userId,
                side: dbSide,
                type: marketType,
                price: executionPrice,
                trigger_price: null,
                qty,
                qty_filled: qty,
                leverage,
                reduce_only: false,
                status: "filled",
            },
            { transaction }
        );

        const position = await DerivativePosition.create(
            {
                userId,
                account_id: account.id,
                market_id: market.id,
                order_id: order.id,
                side: dbSide,
                leverage,
                position_mode: account.margin_mode || "cross",
                isolated_margin: account.margin_mode === "isolated" ? computeRequiredMargin({
                    qty,
                    price: executionPrice,
                    leverage,
                }) : null,
                qty,
                entry_price: executionPrice,
                mark_price: executionPrice,
                unrealized_pnl: 0,
                realized_pnl: 0,
                liquidation_price: null,
                stop_loss: stopLoss,
                take_profit: takeProfit,
                status: "open",
                opened_at: new Date(),
            },
            { transaction }
        );

        await DerivativeTrade.create(
            {
                userId,
                market_id: market.id,
                maker_order_id: null,
                taker_order_id: order.id,
                price: executionPrice,
                qty,
                maker_account_id: null,
                taker_account_id: account.id,
                fee: 0,
                fee_asset_id: null,
            },
            { transaction }
        );

        return { order, position };
    }


    async placeTrade(userId, payload) {
        const clean = validatePayload(payload);

        return sequelize.transaction(async (transaction) => {
            const dbSide = mapSide(clean.side);

            const account = await this.getOrCreateDerivativeAccount({ userId, transaction });

            if (account.status !== "active") {
                throw new Error(`Account is ${account.status}`);
            }

            const market = await this.getMarketBySymbol({
                asset: clean.asset,
                transaction,
            });
            const forexPrice = forexData.getTicker(clean.asset);
            const prices = {
                bid: forexPrice.bid ?? 0.001,
                ask: forexPrice.ask ?? 0.001,
            }

            const qty = computeQtyFromLot(clean.lot);
            const executionPrice = getExecutionPrice({
                dbSide,
                marketType: clean.marketType,
                market: prices,
                limit: clean.limit,
            });

            if (!executionPrice || executionPrice <= 0) {
                throw new Error("Invalid market price");
            }

            validateStops({
                dbSide,
                executionPrice,
                stopLoss: clean.stopLoss,
                takeProfit: clean.takeProfit,
            });


            const requiredMargin = computeRequiredMargin({
                qty,
                price: executionPrice,
                leverage: clean.leverage,
            });



            const balance = toNum(account.balance);
            const marginUsedBefore = toNum(account.margin_used);
            const marginUsedAfter =
                clean.marketType === "market"
                    ? round12(marginUsedBefore + requiredMargin)
                    : marginUsedBefore;

            const accountPreview = computeMarginFields({
                balance,
                unrealizedPnl: 0,
                marginUsed: marginUsedAfter,
            });

            if (clean.marketType === "market" && accountPreview.margin_free < 0) {
                throw new ValidationError("Insufficient free margin");
            }

            let order = null;
            let position = null;

            if (clean.marketType === "market") {
                const result = await this.fillMarketOrderAndOpenPosition({
                    userId,
                    account,
                    market,
                    dbSide,
                    marketType: clean.marketType,
                    leverage: clean.leverage,
                    qty,
                    executionPrice,
                    stopLoss: clean.stopLoss,
                    takeProfit: clean.takeProfit,
                    transaction,
                });

                order = result.order;
                position = result.position;

                await account.update(
                    {
                        margin_used: marginUsedAfter,
                        equity: accountPreview.equity,
                        margin_free: accountPreview.margin_free,
                        margin_level: accountPreview.margin_level,
                    },
                    { transaction }
                );
            } else {
                order = await this.createPendingOrder({
                    userId,
                    account,
                    market,
                    dbSide,
                    marketType: clean.marketType,
                    leverage: clean.leverage,
                    qty,
                    triggerPrice: clean.limit,
                    transaction,
                });
            }
            const positions = await DerivativePosition.findAll({
                where: { userId, status: 'open' },
                order: [['opened_at', 'desc']],
                include: [
                    {
                        model: MarketPair, as: 'pair', include: [
                            { model: Asset, as: 'base' },
                            { model: Asset, as: 'quote' },
                            { model: SymbolStats, as: 'rate' }
                        ]
                    }
                ],
                limit: 5
            })
            const accounts = await DerivativeAccount.findOne({
                where: { user_id: userId }
            })


            return {
                message:
                    clean.marketType === "market"
                        ? `${clean.asset} ${dbSide} position opened`
                        : `${clean.asset} ${clean.marketType} order placed`,
                data: {
                    account: {
                        id: account.id,
                        kind: account.kind,
                        status: account.status,
                        margin_mode: account.margin_mode,
                    },
                    market: {
                        id: market.id,
                        symbol: market.symbol || clean.asset,
                    },
                    order: {
                        id: order.id,
                        side: order.side,
                        type: order.type,
                        status: order.status,
                        qty: Number(order.qty),
                        qty_filled: Number(order.qty_filled),
                        leverage: order.leverage,
                        price: order.price != null ? Number(order.price) : null,
                        trigger_price: order.trigger_price != null ? Number(order.trigger_price) : null,
                    },
                    position: position
                        ? {
                            id: position.id,
                            side: position.side,
                            qty: Number(position.qty),
                            entry_price: Number(position.entry_price),
                            leverage: position.leverage,
                            stop_loss: position.stop_loss != null ? Number(position.stop_loss) : null,
                            take_profit: position.take_profit != null ? Number(position.take_profit) : null,
                            status: position.status,
                        }
                        : null,
                    margin: {
                        required: requiredMargin,
                        used_after:
                            clean.marketType === "market"
                                ? marginUsedAfter
                                : Number(account.margin_used),
                        free_after:
                            clean.marketType === "market"
                                ? accountPreview.margin_free
                                : Number(account.margin_free),
                    },
                },
                positions: positions.map(t => {
                    const baseAsset = t.pair?.base ?? '';
                    const quoteAsset = t.pair?.quote ?? '';
                    const price = t.pair?.rate ?? {};
                    if (!baseAsset && !quoteAsset) return

                    return {
                        id: t.id,
                        symbol: t.pair?.symbol,
                        baseSymbol: baseAsset?.symbol || "—",
                        quoteSymbol: quoteAsset?.symbol || "—",
                        baselogo: getUploadedFile(baseAsset?.logo, 'assets') || null,
                        quotelogo: getUploadedFile(quoteAsset?.logo, 'assets') || null,
                        type: t.side,
                        entryPrice: t.entry_price,
                        price: price?.price,
                        low24h: price?.low24h,
                        high24: price?.high24h,
                        leverage: t.leverage,
                        lots: t.qty || 0,
                        sl: t.stop_loss ?? '-',
                        tp: t.take_profit ?? '-',
                        status: t.status.charAt(0).toUpperCase() + t.status.slice(1),
                        time: new Date(t.opened_at).toISOString().replace('T', ' ').substring(0, 19)
                    }
                }).filter(Boolean),
                account: {
                    balance: accounts.balance,
                    equity: accounts.equity,
                    free: accounts.margin_free,
                    used: accounts.margin_used,
                    level: accounts.margin_level
                },
            };
        });
    };

    async verifyPassword(user, plainPassword) {
        const match = await bcrypt.compare(plainPassword, user.password)
        if (!match) throw Object.assign(new Error('Invalid password.'), { status: 401 })
    }

    /* ─────────────────────────────────────────────────────────────────────────────
       Helper – get or assert active derivative account for the user
    ───────────────────────────────────────────────────────────────────────────── */
    async getActiveDerivativeAccount(userId, transaction) {
        const account = await DerivativeAccount.findOne({
            where: { user_id: userId },   // add kind: 'forex_cfd' if needed
            lock: transaction.LOCK.UPDATE,
            transaction,
        })

        if (!account) throw new ConflictError('Trading account not found.')
        if (account.status !== 'active')
            throw new BadRequestError('Trading account is not active.')

        return account
    }

    async closeTrade(userId, payload ) {
        const {positionId} = payload;
        return sequelize.transaction(async (transaction) => {

            // 1. Fetch position with lock to prevent race conditions
            const position = await DerivativePosition.findOne({
                where: { id: positionId, userId, status: 'open' },
                lock: transaction.LOCK.UPDATE,
                transaction,
            });

            if (!position) throw new NotFoundError('Open position not found.');

            if (position.status !== 'open') throw new BadRequestError('Position is not open.');

            // 2. Fetch account with lock
            const account = await this.getActiveDerivativeAccount(userId, transaction);

            // 3. Get current market price for the asset
            const market = await MarketPair.findByPk(position.market_id, { transaction });
            if (!market) throw new NotFoundError('Market not found.');

            const forexPrice = forexData.getTicker(market.symbol);
            if (!forexPrice) throw new Error(`No live price for ${market.symbol?.replace("_" , "/")}`);

            // 4. Determine exit price based on side
            //    Long closes at BID (you sell), Short closes at ASK (you buy back)
            const exitPrice =
                position.side === 'long'
                    ? (forexPrice.bid ?? 0)
                    : (forexPrice.ask ?? 0);

            if (!exitPrice || exitPrice <= 0) throw new Error('Invalid exit price.');

            // 5. Calculate PnL
            //    Long:  (exitPrice - entryPrice) * qty
            //    Short: (entryPrice - exitPrice) * qty
            const entryPrice = toNum(position.entry_price);
            const qty = toNum(position.qty);

            const rawPnl =
                position.side === 'long'
                    ? (exitPrice - entryPrice) * qty
                    : (entryPrice - exitPrice) * qty;

            const realizedPnl = round12(rawPnl);

            // 6. Release margin that was locked for this position
            const marginReleased = round12(
                (entryPrice * qty) / (position.leverage || 1)
            );

            // 7. Recompute account fields
            const prevBalance = toNum(account.balance);
            const prevMarginUsed = toNum(account.margin_used);
            const prevEquity = toNum(account.equity);

            const newBalance = round12(prevBalance + realizedPnl);  // profit/loss hits balance on close
            const newMarginUsed = round12(Math.max(0, prevMarginUsed - marginReleased));

            const accountPreview = computeMarginFields({
                balance: newBalance,
                unrealizedPnl: 0,             // this position is closed; others handled by mark-to-market
                marginUsed: newMarginUsed,
            });

            // 8. Close the position
            await position.update(
                {
                    status: 'closed',
                    mark_price: exitPrice,
                    realized_pnl: realizedPnl,
                    unrealized_pnl: 0,
                    closed_at: new Date(),
                },
                { transaction }
            );

            // 9. Update account
            await account.update(
                {
                    balance: newBalance,
                    equity: accountPreview.equity,
                    margin_used: newMarginUsed,
                    margin_free: accountPreview.margin_free,
                    margin_level: accountPreview.margin_level,
                },
                { transaction }
            );

            // 10. Record transaction
            /* await Transaction.create(
                {
                    userId,
                    source: 'trading',
                    toType: 'internal',
                    kind: 'trade_close',
                    direction: realizedPnl >= 0 ? 'credit' : 'debit',
                    currency: 'USD',
                    description: `Closed ${position.side} position on ${market.symbol?.replace("_" , "/")} @ ${exitPrice}`,
                    amount: Math.abs(realizedPnl),
                    netAmount: Math.abs(realizedPnl),
                    status: 'completed',
                },
                { transaction }
            ); */

            return {
                message: `${market.symbol} ${position.side} position closed`,
                data: {
                    position: {
                        id: position.id,
                        symbol: market.symbol,
                        side: position.side,
                        qty: qty,
                        entry_price: entryPrice,
                        exit_price: exitPrice,
                        realized_pnl: realizedPnl,
                        leverage: position.leverage,
                        status: 'closed',
                        closed_at: new Date().toISOString(),
                    },
                    account: {
                        balance: account.balance,
                        equity: account.equity,
                        free: account.margin_free,
                        used: account.margin_used,
                        level: account.margin_level,
                    },
                },
            };
        });
    }

    /* ─────────────────────────────────────────────────────────────────────────────
       Helper – get the user's main wallet (main balance source)
    ───────────────────────────────────────────────────────────────────────────── */
    async getUserWallet(userId, transaction) {
        const wallet = await UserBalance.findOne({
            where: { user_id: userId },
            lock: transaction.LOCK.UPDATE,
            transaction,
        })

        if (!wallet) throw new ConflictError('User not found.')
        return wallet
    }

    /* ─────────────────────────────────────────────────────────────────────────────
       depositToDerivative
       – Moves `amount` USD from the user's main wallet → derivative account
    ───────────────────────────────────────────────────────────────────────────── */
    async depositToDerivative(userId, amount, plainPassword) {
        if (!Number.isFinite(amount) || amount <= 0)
            throw new BadRequestError('Invalid amount.')

        const user = await User.findByPk(userId)
        if (!user) throw new ConflictError('User not found.')

        const match = user.comparePassword(plainPassword);
        if (!match) throw new ValidationError("Invalid Password");


        return sequelize.transaction(async (t) => {
            const wallet = await this.getUserWallet(userId, t)
            const account = await this.getActiveDerivativeAccount(userId, t)

            const walletBalance = parseFloat(wallet.balance)
            if (walletBalance < amount)
                throw new Error(`Insufficient wallet balance. Available: $${walletBalance.toFixed(2)}`)

            // Deduct from main wallet
            await wallet.update({ balance: walletBalance - amount }, { transaction: t })

            // Credit derivative account
            const prevBalance = parseFloat(account.balance)
            const newBalance = prevBalance + amount
            const newEquity = parseFloat(account.equity) + amount
            const newFree = parseFloat(account.margin_free) + amount

            await account.update(
                {
                    balance: newBalance,
                    equity: newEquity,
                    margin_free: newFree,
                    // margin_level recomputed: equity / margin_used * 100  (guard div-by-zero)
                    margin_level:
                        parseFloat(account.margin_used) > 0
                            ? (newEquity / parseFloat(account.margin_used)) * 100
                            : 0,
                },
                { transaction: t }
            )

            // Transaction record – debit from wallet side
            await Transaction.create(
                {
                    userId,
                    source: 'funding',
                    toType: 'internal',
                    kind: 'derivative_deposit',
                    direction: 'debit',          // money leaves wallet
                    currency: 'USD',
                    description: `Funded Derivative account`,
                    amount,
                    netAmount: amount,
                    status: 'completed',
                },
                { transaction: t }
            )

            // Transaction record – credit on derivative side
            /*  await Transaction.create(
                 {
                     userId,
                     source: 'funding',
                     toType: 'internal',
                     kind: 'derivative_deposit',
                     direction: 'credit',         // money arrives in trading account
                     currency: 'USD',
                     description: `Received deposit in trading account`,
                     amount,
                     netAmount: amount,
                     status: 'completed',
                 },
                 { transaction: t }
             ) */
            /* const accounts = await DerivativeAccount.findOne({
                where: { user_id: userId }
            }) */
            return {
                account: {
                    balance: account.balance,
                    equity: account.equity,
                    free: account.margin_free,
                    used: account.margin_used,
                    level: account.margin_level
                },
                message: 'Funds added successfully.',
                newBalance,
                newEquity,
            }
        })
    }

    /* ─────────────────────────────────────────────────────────────────────────────
       withdrawFromDerivative
       – Moves `amount` USD from the derivative account → user's main wallet
    ───────────────────────────────────────────────────────────────────────────── */
    async withdrawFromDerivative(userId, amount, plainPassword) {
        if (!Number.isFinite(amount) || amount <= 0)
            throw new BadRequestError('Invalid amount.')

        const user = await User.findByPk(userId)
        if (!user) throw new ConflictError('User not found.')

        const match = user.comparePassword(plainPassword);
        if (!match) throw new ValidationError("Invalid Password");


        return sequelize.transaction(async (t) => {
            const wallet = await this.getUserWallet(userId, t)
            const account = await this.getActiveDerivativeAccount(userId, t)

            const freeMargin = parseFloat(account.margin_free)
            if (freeMargin < amount)
                throw new ValidationError(`Insufficient free margin. Available: $${freeMargin.toFixed(2)}`)

            // Deduct from derivative account
            const newBalance = parseFloat(account.balance) - amount
            const newEquity = parseFloat(account.equity) - amount
            const newFree = freeMargin - amount
            const marginUsed = parseFloat(account.margin_used)

            await account.update(
                {
                    balance: newBalance,
                    equity: newEquity,
                    margin_free: newFree,
                    margin_level: marginUsed > 0 ? (newEquity / marginUsed) * 100 : 0,
                },
                { transaction: t }
            )

            // Credit main wallet
            await wallet.update(
                { balance: parseFloat(wallet.balance) + amount },
                { transaction: t }
            )

            // Transaction record – debit from derivative side


            // Transaction record – credit on wallet side
            await Transaction.create(
                {
                    userId,
                    source: 'funding',
                    toType: 'internal',
                    kind: 'derivative_withdrawal',
                    direction: 'credit',         // money arrives in main wallet
                    currency: 'USD',
                    description: `Received withdrawal from derivative account`,
                    amount,
                    netAmount: amount,
                    status: 'completed',
                },
                { transaction: t }
            )

            /* const accounts = await DerivativeAccount.findOne({
                where: { user_id: userId }
            }) */
            return {
                message: 'Withdrawal successful.',
                account: {
                    balance: account.balance,
                    equity: account.equity,
                    free: account.margin_free,
                    used: account.margin_used,
                    level: account.margin_level
                },
                newBalance,
                newEquity,
            }
        })
    }
}

module.exports = new ForexService();


