const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const moment_timeZone = require('moment-timezone');

// import helpers function
const {
    toStr,
    checkRequestAuth,
    getOtp,
    sendMessage,
    getUserRandomToken,
    capitalizeWords,
    getMsgAccordingToTime,
    declareDessawar,
    checkGameStatus,
    resultDeclare,
    checkGameStatusForBid,
    getMsgAccordingToTimeRouletteActive,
    getPossibleCombination,
    convert12To24, getMsgAccordingToOpenTime,
    checkGameOpenStatus,
    notificationSender,
    noticeSender,
} = require('../helper/helper_functions');

const getShortMonthName = require('../utils/getShortMonthName')
const parseCustomDate = require('../utils/parseCustomDate')

// db modules
const file_module = require('../model/file_module');
const user_module = require('../model/user_module');
const fix_values_module = require('../model/fix_values_module');
const wallet_trans_history_module = require('../model/wallet_trans_history_module');
const user_device_record_module = require('../model/user_device_record_module');
const contact_settings_module = require('../model/contact_settings_module');
const state_module = require('../model/state_module');
const district_module = require('../model/district_module');
const user_address_module = require('../model/user_address_module');
const user_bank_details_module = require('../model/user_bank_details_module');
const admin_bank_detail_module = require('../model/admin_bank_detail_module');
const add_funds_module = require('../model/add_funds_module');
const game_rates_module = require('../model/game_rates_module');
const withdraw_fund_request_module = require('../model/withdraw_fund_request_module');
const notice_module = require('../model/notice_module');
const how_to_play_module = require('../model/how_to_play_module');
const bid_history_module = require('../model/bid_history_module');
const player_ids_module = require('../model/player_ids_module');
const app_link_module = require('../model/app_link_module');
const app_setting_module = require('../model/app_setting_module')
const weekday_games_module = require('../model/weekday_games_module')
const games_module = require('../model/games_module')
const gali_disswar_games_module = require('../model/gali_disswar_games_module')
const game_result_history_module = require('../model/game_result_history_module')
const lottery_module = require('../model/lottery_module')
const lottery_result_history_module = require('../model/lottery_result_history_module')
const slider_images_module = require('../model/slider_images_module')
const lottery_tickets_module = require('../model/lottery_tickets_module')
const lottery_bid_history_module = require('../model/lottery_bid_history_module')
const ideas_module = require('../model/ideas_module')
const refer_details_module = require('../model/refer_details_module')
const starline_games_module = require('../model/starline_games_module')
const starline_game_result_history_module = require('../model/starline_game_result_history_module')
const gali_disswar_bid_history_module = require('../model/gali_disswar_bid_history_module')
const roulette_game_module = require('../model/roulette_game_module')
const roulette_bid_history_module = require('../model/roulette_bid_history_module')
const roulette_result_hisory_module = require('../model/roulette_result_hisory_module')
const single_pana_numbers_module = require('../model/single_pana_numbers_module')
const double_pana_numbers_module = require('../model/double_pana_numbers_module')
const tripple_pana_numbers_module = require('../model/tripple_pana_numbers_module')
const chat_msg_module = require('../model/chat_msg_module')
const user_notification_module = require('../model/user_notification_module')
const tips_module = require('../model/tips_module')
const starline_game_rates_module = require('../model/starline_game_rates_module');
const starline_bid_history_module = require('../model/starline_bid_history_module');
const gali_disswar_game_rates_module = require('../model/gali_disswar_game_rates_module');
const gali_disswar_game_result_history_module = require('../model/gali_disswar_game_result_history_module');
const qrcode_images_module = require('../model/qrcode_images_module');

const { get12HoursTimeFromISO } = require('../utils/getTimeFromISO')
const { formatDateToDDMMYYYY, getWeekdayNameInIST } = require('../utils/formatDateFromISO');
const mini_games_module = require('../model/mini_games_module');
const admin_module = require('../model/admin_module');
const content_rules_module = require('../model/contents_rules_module');


// const PaymentGatewayService = require('../services/PaymentGatewayService');
const PaymentGateway_settings = require('../model/payment_gateway_module');
const PaymentSettings = require('../model/payment_gateway_module');
const { doPayout } = require("../services/dollarbazar.payout.service");




const lobbyData = async (req, res) => {

    try {

        let data = {};

        if (!req.user) {
            return res.status(401).json({ success: false, msg: 'UnAuthorized request' });
        }


        req?.user?._id ? data._id = req?.user?._id : '';
        req?.user?.user_name ? data.user_name = req?.user?.user_name : '';
        req?.user?.mobile ? data.mobile = req?.user?.mobile : '';
        req?.user?.wallet_balance ? data.wallet_balance = req?.user?.wallet_balance : '';
        req?.user?.avatar ? data.avatar = req?.user?.avatar : data.avatar = 0;
        req?.user?.my_code ? data.my_code = req?.user?.my_code : '';
        req?.user?.profile_pic ? data.profile_pic = req?.user?.profile_pic : data.profile_pic = '';

        const settings = await fix_values_module.findOne().lean();

        if (!settings) {
            return res.status(404).json({ success: false, msg: 'Settings not found' });
        }

        settings?.marquee ? data.marquee = settings?.marquee : '';

        return res.status(200).json({ success: true, data })

    } catch (error) {

        console.log("ðŸš€ ~ lobbyData ~ error: ", error)

    }

}

const appInfoData = async (req, res) => {

    try {

        let data = await app_link_module.findOne({ status: 1 });

        if (!data) {
            return res.status(404).json({ success: false, msg: 'Settings not found' });
        }

        const newData = data.toObject();
        delete newData.change_logs

        return res.status(200).json({ success: true, newData })

    } catch (error) {
        console.log("ðŸš€ ~ appInfoData ~ error: ", error)
    }
}



const getPublicImages = async (req, res) => {
    try {
        let { image_id } = req.params;


        if (!image_id || !mongoose.isValidObjectId(image_id)) {
            return res.status(400).json({ error: 'Invalid image ID' });
        }

        let image = await file_module.findById(image_id);
        if (!image || !image.fileInfo || !image.fileInfo.fileBuffer) {
            return res.status(404).json({ error: 'Image not found' });
        }

        const imageBuffer = Buffer.from(image.fileInfo.fileBuffer);

        res.writeHead(200, {
            'Content-Type': image.fileInfo.content_type,
            'Content-Length': imageBuffer.length
        });

        res.end(imageBuffer);
    } catch (error) {
        console.error("Error fetching image:", error);
        res.status(500).json({ error: 'Server error' });
    }
};











// Extract the data logic into a separate function
const getGameChartData = async (gameDB_id) => {
    try {
        const results = await game_result_history_module
            .find({ gameDB_id: gameDB_id })
            .sort({ result_date: 1 })
            .populate('gameDB_id')
            .lean();

        if (results.length === 0) {
            const today = new Date();
            today.setHours(0, 0, 0, 0);

            const currentMonday = new Date(today);
            const currentDay = today.getDay();
            const diffToMonday = currentDay === 0 ? -6 : 1 - currentDay;
            currentMonday.setDate(today.getDate() + diffToMonday);

            const currentSunday = new Date(currentMonday);
            currentSunday.setDate(currentMonday.getDate() + 6);

            const daysOfWeek = ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"];
            const currentWeekDays = {};

            daysOfWeek.forEach((day, index) => {
                const dayDate = new Date(currentMonday);
                dayDate.setDate(currentMonday.getDate() + index);
                const isFuture = dayDate > today;

                currentWeekDays[day] = {
                    digit: isFuture ? '' : '**',
                    open_pana: isFuture ? '' : '***',
                    close_pana: isFuture ? '' : '***',
                    date: dayDate,
                    hasData: false,
                    isFuture: isFuture
                };
            });

            const weeklyData = [{
                startDate: formatDate(currentMonday),
                endDate: formatDate(currentSunday),
                days: currentWeekDays
            }];

            return {
                title: "Game Result Chart",
                banner_title: "Matka Result Chart",
                weeklyData: weeklyData
            };
        }

        const getFormattedEntry = (date, result = null) => {
            const week_name = getWeekdayNameInIST(date, true);
            const today = new Date();
            today.setHours(0, 0, 0, 0);
            const currentDate = new Date(date);
            currentDate.setHours(0, 0, 0, 0);

            const isFutureDate = currentDate > today;

            if (!result) {
                return {
                    week_name,
                    digit: isFutureDate ? '' : '**',
                    open_pana: isFutureDate ? '' : '***',
                    close_pana: isFutureDate ? '' : '***',
                    date: new Date(date),
                    hasData: false,
                    isFuture: isFutureDate
                };
            }

            let digit = '';

            if (result?.open_number && result?.open_decleare_date) {
                const str = result.open_number.toString();
                const digits = str.slice(0, 3).split('').map(Number);
                const open_res = (digits[0] + digits[1] + digits[2]) % 10;
                digit += open_res;
            } else {
                digit += isFutureDate ? '' : '*';
            }

            if (result?.close_number && result?.close_decleare_date) {
                const str = result.close_number.toString();
                const digits = str.slice(0, 3).split('').map(Number);
                const close_res = (digits[0] + digits[1] + digits[2]) % 10;
                digit += close_res;
            } else {
                digit += isFutureDate ? '' : '*';
            }

            return {
                week_name,
                digit,
                open_pana: result?.open_decleare_date ? result?.open_number : (isFutureDate ? '' : '***'),
                close_pana: result?.close_decleare_date ? result?.close_number : (isFutureDate ? '' : '***'),
                date: new Date(date),
                hasData: true,
                isFuture: isFutureDate
            };
        };

        // Rest of your data processing logic...
        const startDate = new Date(results[0].result_date);
        const endDate = new Date(results[results.length - 1].result_date);
        const today = new Date();
        today.setHours(0, 0, 0, 0);

        const allEntries = [];
        const firstMonday = new Date(startDate);
        const firstDay = firstMonday.getDay();
        const diffToMonday = firstDay === 0 ? -6 : 1 - firstDay;
        firstMonday.setDate(firstMonday.getDate() + diffToMonday);

        const endOfCurrentWeek = new Date(today);
        const currentDay = today.getDay();
        const diffToSunday = currentDay === 0 ? 0 : 7 - currentDay;
        endOfCurrentWeek.setDate(today.getDate() + diffToSunday);

        let currentDate = new Date(firstMonday);

        while (currentDate <= endOfCurrentWeek) {
            const currentResult = results.find(result => {
                const resultDate = new Date(result.result_date);
                return resultDate.toDateString() === currentDate.toDateString();
            });

            allEntries.push(getFormattedEntry(new Date(currentDate), currentResult));
            currentDate.setDate(currentDate.getDate() + 1);
        }

        const weeklyData = [];
        const daysOfWeek = ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"];

        for (let i = 0; i < allEntries.length; i += 7) {
            const weekEntries = allEntries.slice(i, i + 7);

            if (weekEntries.length === 0) continue;

            const weekStartDate = weekEntries[0]?.date;
            let weekEndDate = new Date(weekStartDate);
            weekEndDate.setDate(weekEndDate.getDate() + 6);

            const weekDays = {};
            daysOfWeek.forEach((day, index) => {
                const entryDate = new Date(weekStartDate);
                entryDate.setDate(entryDate.getDate() + index);

                const existingEntry = weekEntries[index];

                if (existingEntry) {
                    weekDays[day] = existingEntry;
                } else {
                    const today = new Date();
                    today.setHours(0, 0, 0, 0);
                    const isFuture = entryDate > today;

                    const resultForDate = results.find(result => {
                        const resultDate = new Date(result.result_date);
                        return resultDate.toDateString() === entryDate.toDateString();
                    });

                    if (resultForDate) {
                        weekDays[day] = getFormattedEntry(entryDate, resultForDate);
                    } else {
                        weekDays[day] = {
                            week_name: day,
                            digit: isFuture ? '' : '**',
                            open_pana: isFuture ? '' : '***',
                            close_pana: isFuture ? '' : '***',
                            date: entryDate,
                            hasData: false,
                            isFuture: isFuture
                        };
                    }
                }
            });

            const week = {
                startDate: formatDate(weekStartDate),
                endDate: formatDate(weekEndDate),
                days: weekDays
            };

            weeklyData.push(week);
        }

        function formatDate(date) {
            const day = date.getDate().toString().padStart(2, '0');
            const month = (date.getMonth() + 1).toString().padStart(2, '0');
            const year = date.getFullYear().toString().slice(-2);
            return `${day}/${month}/${year}`;
        }

        function getWeekdayNameInIST(date, short = false) {
            const shortDays = ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'];
            const dayIndex = date.getDay();
            return shortDays[dayIndex];
        }

        return {
            title: "Game Result Chart",
            banner_title: `Matka ${results[0].gameDB_id.game_name} Result Chart`,
            weeklyData: weeklyData
        };

    } catch (error) {
        console.error('Error in getGameChartData:', error);
        throw error;
    }
};

// Then create separate controller functions
const gamePanelChart = async (req, res) => {
    try {
        const gameDB_id = req?.params?.gameDB_id;
        const chartData = await getGameChartData(gameDB_id);

        chartData.weeklyData.map((d) => {
            console.log("week day data ", d)
        })

        res.render('game_chart', {
            title: chartData.title,
            banner_title: chartData.banner_title,
            weeklyData: chartData.weeklyData
        });
    } catch (error) {
        console.error('Error in gameJodiChart:', error);
        res.status(500).send('Internal Server Error');
    }
};

const gameJodiChart = async (req, res) => {
    try {
        const gameDB_id = req?.params?.gameDB_id;
        const chartData = await getGameChartData(gameDB_id);

        res.render('game_chart_jodi', {
            title: chartData.title + " - Simple",
            banner_title: chartData.banner_title,
            weeklyData: chartData.weeklyData
        });
    } catch (error) {
        console.error('Error in gamePanelChart:', error);
        res.status(500).send('Internal Server Error');
    }
};

const gameResultChart_details = async (req, res) => {
    try {
        const games_list = await starline_games_module.find({}, 'game_name').lean();

        let allDatesSet = new Set();

        const results = await Promise.all(
            games_list.map(async (v) => {
                const gameDB_id = v._id;
                const data = await starline_game_result_history_module
                    .find({ gameDB_id })
                    .sort({ result_date: 1 })
                    .lean();

                data.forEach(d => {
                    allDatesSet.add(new Date(d.result_date).toISOString().split("T")[0]);
                });

                return {
                    game_name: v.game_name,
                    data,
                };
            })
        );

        const allDates = Array.from(allDatesSet).sort(); // YYYY-MM-DD format strings

        function getOpenResultDigit(open_number) {
            if (!open_number) return '*';

            const str = open_number.toString().slice(0, 3); // first 3 digits
            const sum = str
                .split('')
                .map(Number)
                .reduce((acc, val) => acc + val, 0);

            return sum % 10;
        }

        const normalizedResults = results.map(game => {
            const dateMap = new Map(
                game.data.map(d => [new Date(d.result_date).toISOString().split("T")[0], {
                    ...d,
                    result_date: moment_timeZone.tz(d.result_date, "Asia/Kolkata").format("DD-MMM-YYYY"),
                    digit: getOpenResultDigit(d.open_number)
                }])
            );

            const fullData = allDates.map(dateStr => {
                return dateMap.get(dateStr) || {
                    result_date: moment_timeZone.tz(dateStr, "Asia/Kolkata").format("DD-MMM-YYYY"),
                    open_number: null,
                    open_decleare_date: null,
                    digit: '*'
                };
            });

            return {
                game_name: game?.game_name,
                data: fullData, // Removed reverse() to maintain chronological order
            };
        });

        res.render('game_chart_details', {
            title: "Game Result Chart",
            banner_title: "Matka STARLINE Result Chart",
            chartData: normalizedResults,
            allDates,
        });

    } catch (error) {
        console.error('Error in gameResultChart:', error);
        res.status(500).send('Internal Server Error');
    }
};











const gameResult_galidessar_chart_details = async (req, res) => {
    try {
        const games_list = await gali_disswar_games_module.find({}, 'game_name').lean();

        let allDatesSet = new Set();

        const results = await Promise.all(
            games_list.map(async (v) => {
                const gameDB_id = v._id;
                const data = await gali_disswar_game_result_history_module
                    .find({ gameDB_id })
                    .sort({ result_date: 1 })
                    .lean();

                data.forEach(d => {
                    allDatesSet.add(new Date(d.result_date).toISOString().split("T")[0]);
                });

                return {
                    game_name: v.game_name,
                    data,
                };
            })
        );

        const allDates = Array.from(allDatesSet).sort(); // YYYY-MM-DD format strings

        function getOpenResultDigit(open_number) {
            if (!open_number) return '*';

            const str = open_number.toString().slice(0, 3); // first 3 digits
            const sum = str
                .split('')
                .map(Number)
                .reduce((acc, val) => acc + val, 0);

            return sum % 10;
        }

        const normalizedResults = results.map(game => {
            const dateMap = new Map(
                game.data.map(d => [new Date(d.result_date).toISOString().split("T")[0], { ...d, result_date: moment_timeZone.tz(d.result_date, "Asia/Kolkata").format("DD-MMM-YYYY"), digit: getOpenResultDigit(d.open_number) }])
            );

            const fullData = allDates.map(dateStr => {

                return dateMap.get(dateStr) || {
                    result_date: moment_timeZone.tz(dateStr, "Asia/Kolkata").format("DD-MMM-YYYY"),
                    open_number: null,
                    open_decleare_date: null,
                };
            });

            return {
                game_name: game?.game_name,
                data: fullData?.reverse(),
            };
        });

        res.render('game_chart_details', {
            title: "Game Result Chart",
            banner_title: "Matka Jackpot Result Chart",
            chartData: normalizedResults,
            allDates,
        });

    } catch (error) {
        console.error('Error in gameResultChart:', error);
        res.status(500).send('Internal Server Error');
    }
};

const apiLogout_state_update = async (req, res) => {
    try {
        const userData = req?.user;

        if (!userData || !userData._id) {
            return res.status(401).json({ success: false, msg: "Unauthorized or user data not found." });
        }

        userData.logout_status = 1;
        // userData.unique_jwt_token = ''
        await userData.save();

        return res.status(200).json({ success: true, msg: "User logout status updated successfully." });
    } catch (error) {
        console.error('Error in apiLogout_state_update:', error);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

// middleware not used for JWT token
const apiGetAppKey = async (req, res) => {
    try {
        const env_type = (req?.body?.env_type || '').trim();

        if (typeof env_type !== 'string') {
            env_type = String(env_type)
        }

        if (!env_type.trim()) {
            return res.status(400).json({
                success: false,
                msg: 'env_type is required in request body.',
            });
        }

        if (env_type === '1') {
            return res.json({
                success: true,
                app_key: process.env.APP_KEY,
                msg: 'Success',
            });
        } else if (env_type === 'Prod') {
            const key = process.env.PRODUCTION_APP_KEY_APP + process.env.PRODUCTION_APP_KEY_SERVER;
            return res.json({
                success: true,
                app_key: key,
                msg: 'Success',
            });
        } else {
            return res.status(400).json({
                success: false,
                msg: 'Invalid env_type provided.',
            });
        }

    } catch (err) {
        console.error('Error in apiGetAppKey:', err);
        return res.status(500).json({
            success: false,
            msg: 'Internal Server Error',
        });
    }
};

// middleware not used for JWT token
const apiCheckMobile = async (req, res) => {
    try {
        let { mobile = "", app_key = "", env_type = "" } = req?.body || {};
        app_key = toStr(app_key)
        env_type = toStr(env_type)

        if (!app_key || !env_type || !mobile) {
            return res
                .status(400)
                .json({ success: false, msg: 'All fields are required.' });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res
                .status(401)
                .json({ success: false, msg: 'Unauthorized request.' });
        }

        mobile = Number(toStr(mobile));

        if (!mobile) {
            return res.status(400).json({ success: false, msg: 'Mobile number is required.' });
        }

        const mobileRegex = /^\d{10}$/;

        if (!mobileRegex.test(mobile)) {
            return res.status(400).json({ success: false, msg: 'Invalid mobile number. Must be exactly 10 digits.' });
        }

        let userData = await user_module.findOne({ mobile }).lean();

        if (userData) {
            return res.json({
                success: false,
                msg: 'Mobile number is already registered. Try Login.',
            });
        } else {
            return res.json({
                success: true,
                msg: 'Mobile number is not registered.',
            });
        }

    } catch (err) {
        console.error('Error in apiCheckMobile:', err.message || err);
        return res.status(500).json({
            success: false,
            msg: 'Internal Server Error',
        });
    }
};

// middleware not used for JWT token
const apiCheckUsername = async (req, res) => {
    try {
        const username = toStr(req?.body?.username || '').toLowerCase();
        if (!username) {
            return res
                .status(400)
                .json({ success: false, msg: 'Username is required.' });
        }

        let usernameIsExist = await user_module.findOne({ user_name: username })
        if (usernameIsExist) {
            return res.json({
                success: false,
                msg: 'Username is already registered. Try login.'
            });
        }

        return res.json({
            success: true,
            msg: 'Username is not registered.'
        });
    } catch (err) {
        console.error('Error in apiCheckUsername:', err);
        return res
            .status(500)
            .json({ success: false, msg: 'Internal Server Error' });
    }
};


// New updated apis for 99sms services

// middleware not used for JWT token
const apiOtpSent = async (req, res) => {
    try {
        let { mobile = "", app_key = "", env_type = "" } = req?.body || {};
        mobile = Number(toStr(mobile));
        app_key = toStr(app_key);
        env_type = toStr(env_type);

        if (!app_key || !env_type) {
            return res
                .status(400)
                .json({ success: false, msg: 'All fields are required.' });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res
                .status(401)
                .json({ success: false, msg: 'Unauthorized request.' });
        }

        if (!mobile) {
            return res
                .status(400)
                .json({ success: false, msg: 'Mobile number is required.' });
        }

        if (!/^\d{10}$/.test(mobile)) {
            return res
                .status(400)
                .json({
                    success: false,
                    msg: 'Invalid mobile number. Must be exactly 10 digits.'
                });
        }

        // let userData = await user_module.findOne({ mobile }).lean();

        // if (!userData) {
        //     return res
        //         .status(401)
        //         .json({ success: false, msg: 'User not found.' });
        // }

        const otp = getOtp(mobile);
        console.log("🚀 ~ apiOtpSent ~ otp:", otp)

        if (otp !== 1234) {
            await sendMessage(mobile, otp.toString());
        }

        // (omit sending OTP value in production)
        return res.json({ success: true, otp });
    } catch (error) {
        console.error('Error in apiOtpSent:', error);
        return res
            .status(500)
            .json({ success: false, msg: 'Internal Server Error' });
    }
};

// middleware not used for JWT token
const apiResendOtp = async (req, res) => {
    try {
        let { mobile = "", app_key = "", env_type = "" } = req?.body || {};
        mobile = Number(toStr(mobile));
        app_key = toStr(app_key);
        env_type = toStr(env_type);

        if (!app_key || !env_type) {
            return res
                .status(400)
                .json({ success: false, msg: 'All fields are required.' });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res
                .status(401)
                .json({ success: false, msg: 'Unauthorized request.' });
        }

        if (!mobile) {
            return res
                .status(400)
                .json({ success: false, msg: 'Mobile number is required.' });
        }
        if (!/^\d{10}$/.test(mobile)) {
            return res
                .status(400)
                .json({ success: false, msg: 'Invalid mobile number. Must be exactly 10 digits.' });
        }

        let userData = await user_module.findOne({ mobile }).lean();

        if (!userData) {
            return res
                .status(401)
                .json({ success: false, msg: 'User not found.' });
        }

        const otp = await getOtp(mobile);

        if (otp !== 1234) {
            const message = `${otp} is your OTP. Please do not share it.`;
            await sendMessage(mobile, message);
        }

        return res.json({
            success: true,
            msg: 'OTP re-sent successfully.',
            otp  // Remove this in production!
        });
    } catch (error) {
        console.error('Error in apiResendOtp:', error);
        return res
            .status(500)
            .json({ success: false, msg: 'Internal Server Error' });
    }
};




// // middleware not used for JWT token
// const apiOtpSent = async (req, res) => {
//     try {
//         let { mobile = "", app_key = "", env_type = "" } = req?.body || {};
//         mobile = Number(toStr(mobile));
//         app_key = toStr(app_key);
//         env_type = toStr(env_type);

//         if (!app_key || !env_type) {
//             return res
//                 .status(400)
//                 .json({ success: false, msg: 'All fields are required.' });
//         }

//         if (!checkRequestAuth(app_key, env_type)) {
//             return res
//                 .status(401)
//                 .json({ success: false, msg: 'Unauthorized request.' });
//         }

//         if (!mobile) {
//             return res
//                 .status(400)
//                 .json({ success: false, msg: 'Mobile number is required.' });
//         }

//         if (!/^\d{10}$/.test(mobile)) {
//             return res
//                 .status(400)
//                 .json({
//                     success: false,
//                     msg: 'Invalid mobile number. Must be exactly 10 digits.'
//                 });
//         }

//         // let userData = await user_module.findOne({ mobile }).lean();

//         // if (!userData) {
//         //     return res
//         //         .status(401)
//         //         .json({ success: false, msg: 'User not found.' });
//         // }

//         const otp = getOtp(mobile);

//         if (otp !== 1234) {
//             await sendMessage(mobile, otp.toString());
//         }

//         // (omit sending OTP value in production)
//         return res.json({ success: true, otp });
//     } catch (error) {
//         console.error('Error in apiOtpSent:', error);
//         return res
//             .status(500)
//             .json({ success: false, msg: 'Internal Server Error' });
//     }
// };

// // middleware not used for JWT token
// const apiResendOtp = async (req, res) => {
//     try {
//         let { mobile = "", app_key = "", env_type = "" } = req?.body || {};
//         mobile = Number(toStr(mobile));
//         app_key = toStr(app_key);
//         env_type = toStr(env_type);

//         if (!app_key || !env_type) {
//             return res
//                 .status(400)
//                 .json({ success: false, msg: 'All fields are required.' });
//         }

//         if (!checkRequestAuth(app_key, env_type)) {
//             return res
//                 .status(401)
//                 .json({ success: false, msg: 'Unauthorized request.' });
//         }

//         if (!mobile) {
//             return res
//                 .status(400)
//                 .json({ success: false, msg: 'Mobile number is required.' });
//         }
//         if (!/^\d{10}$/.test(mobile)) {
//             return res
//                 .status(400)
//                 .json({ success: false, msg: 'Invalid mobile number. Must be exactly 10 digits.' });
//         }

//         let userData = await user_module.findOne({ mobile }).lean();

//         if (!userData) {
//             return res
//                 .status(401)
//                 .json({ success: false, msg: 'User not found.' });
//         }

//         const otp = await getOtp(mobile);

//         if (otp !== 1234) {
//             const message = `${otp} is your OTP. Please do not share it.`;
//             await sendMessage(mobile, message);
//         }

//         return res.json({
//             success: true,
//             msg: 'OTP re-sent successfully.',
//             otp  // Remove this in production!
//         });
//     } catch (error) {
//         console.error('Error in apiResendOtp:', error);
//         return res
//             .status(500)
//             .json({ success: false, msg: 'Internal Server Error' });
//     }
// };

// middleware not used for JWT token
// const apiUserRegistration = async (req, res) => {
//     const session = await mongoose.startSession();

//     try {
//         if (!process?.env?.JWT_SECRET) {
//             return res.status(500).json({ success: false, msg: "JWT secret not found" });
//         }

//         await session.withTransaction(async () => {
//             let {
//                 app_key = "",
//                 env_type = "",
//                 username = "",
//                 mobile = "",
//                 password = "",
//                 // security_pin = "",
//                 refer_code = ''
//             } = req?.body || {};

//             app_key = toStr(app_key);
//             env_type = toStr(env_type);
//             username = toStr(username);
//             mobile = toStr(mobile);
//             password = toStr(password);
//             // security_pin = toStr(security_pin);
//             refer_code = toStr(refer_code);

//             // if (!app_key || !env_type || !username || !mobile || !security_pin) {
//             //     throw new Error("All fields are required.");
//             // }

//             if (!app_key || !env_type || !username || !mobile || !password) {
//                 res.json({
//                     success: false,
//                     msg: "All fields are required."
//                 })
//             }

//             if (!checkRequestAuth(app_key, env_type)) {
//                 throw new Error("Unauthorized request.");
//             }

//             const mobileRegex = /^\d{10}$/;
//             // const pinRegex = /^\d{4}$/;
//             // const passRegex = /^(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*()_\-+=\[{\]};:'",<.>/?\\|`~]).{8,}$/

//             if (password.length < 8) {
//                 res.json({
//                     success: false,
//                     msg: "Password invalid: Minimum 8 characters, 1 uppercase, 1 number, 1 special character required."
//                 })
//             }

//             if (!mobileRegex.test(mobile)) {
//                 throw new Error("Invalid mobile. Must be 10 digits.");
//             }
//             // if (!pinRegex.test(security_pin)) {
//             //     throw new Error("Security pin must be 4 digits.");
//             // }

//             const mobileNum = Number(mobile);
//             const exists = await user_module
//                 .findOne({ $or: [{ mobile: mobileNum }, { username }] })
//                 .session(session)
//                 .lean();

//             if (exists) {
//                 throw new Error("Mobile or username already registered.");
//             }

//             let referByUser = null;
//             if (refer_code) {
//                 referByUser = await user_module
//                     .findOne({ my_code: refer_code })
//                     .session(session)
//                     .lean();

//                 console.log(`(((((((()))))) ~ mobileController.js:704 ~ apiUserRegistration ~ referByUser:`, referByUser);
//                 if (!referByUser) {
//                     throw new Error("Invalid refer code.");
//                 }
//             }

//             const settings = await fix_values_module.findOne().session(session).lean();

//             console.log(`(((((((()))))) ~ mobileController.js:710 ~ apiUserRegistration ~ settings:`, settings);
//             const welcome_bonus = settings?.welcome_bonus || 0;



//             const pinNumber = Number(security_pin);
//             // const pinNumber = "1234"
//             const my_code = getUserRandomToken(8, true);
//             // const my_code = "1234";

//             // ðŸ” Hash password before storing
//             const hashedPassword = await bcrypt.hash(password, 10);

//             const newUserData = {
//                 user_name: username,
//                 mobile: mobileNum,
//                 password: hashedPassword,
//                 security_pin: pinNumber,
//                 refer_code: refer_code || undefined,
//                 my_code,
//                 wallet_balance: welcome_bonus,
//             };

//             // console.log(`(((((((()))))) ~ mobileController.js:728 ~ apiUserRegistration ~ newUserData:`, newUserData);

//             const createdUser = await user_module.create([newUserData], { session });
//             const created = createdUser?.[0];

//             if (referByUser) {
//                 await refer_details_module.create([{
//                     refer_to: created._id,
//                     refer_by: referByUser._id,
//                     refer_code,
//                     bonus: welcome_bonus
//                 }], { session });
//             }

//             if (welcome_bonus > 0) {
//                 await wallet_trans_history_module.create([{
//                     userDB_id: created._id,
//                     amount: welcome_bonus,
//                     transaction_type: 1,
//                     before_wallet: 0,
//                     transaction_note: 'User Welcome Bonus',
//                     amount_status: 6,
//                     tx_request_number: getUserRandomToken()
//                 }], { session });

//                 // Notifications are external side-effects: better outside the transaction
//                 // But you may still call it here if you want to block on it
//                 await new user_notification_module({ userDB_id: created._id, msg: `ðŸŽ‰ Welcome to our platform! Youâ€™ve received your Welcome Bonus â‚¹${welcome_bonus}. Good luck! ðŸ€` }).save({ session });
//             }

//             // const unique_jwt_token = jwt.sign(
//             //     { user: created._id },
//             //     process.env.JWT_SECRET,
//             //     { expiresIn: "30d" }   // optional, but recommended
//             // );

//             // created.unique_jwt_token = unique_jwt_token;
//             await created.save({ session });

//             return res.json({
//                 success: true,
//                 // unique_jwt_token,
//                 user_name: created.user_name,
//                 mobile: created.mobile,
//                 msg: 'You are successfully registered.'
//             });
//         });

//     } catch (error) {
//         console.error('Error in apiUserRegistration:', error);
//         return res.status(500).json({
//             success: false,

//             msg: error?.message || 'Internal Server Error'
//         });
//     } finally {
//         session.endSession();
//     }
// };

const apiUserRegistration = async (req, res) => {
    try {
        if (!process?.env?.JWT_SECRET) {
            return res.status(500).json({
                success: false,
                msg: "JWT secret not found"
            });
        }

        let {
            app_key = "",
            env_type = "",
            username = "",
            mobile = "",
            password = "",
            refer_code = '',
            security_pin = ''
        } = req?.body || {};

        app_key = toStr(app_key);
        env_type = toStr(env_type);
        username = toStr(username);
        mobile = toStr(mobile);
        password = toStr(password);
        refer_code = toStr(refer_code);
        security_pin = toStr(security_pin);

        /* ---------------- VALIDATIONS ---------------- */
        if (!app_key || !env_type || !username || !mobile || !password || !security_pin) {
            return res.status(400).json({
                success: false,
                msg: "All fields are required."
            });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res.status(401).json({
                success: false,
                msg: "Unauthorized request."
            });
        }

        if (password.length < 6) {
            return res.status(400).json({
                success: false,
                msg: "Password must be 6 characters."
            });
        }

        if (!/^\d{10}$/.test(mobile)) {
            return res.status(400).json({
                success: false,
                msg: "Invalid mobile. Must be 10 digits."
            });
        }

        const mobileNum = Number(mobile);

        const exists = await user_module.findOne({
            $or: [{ mobile: mobileNum }, { username }]
        }).lean();

        if (exists) {
            return res.status(400).json({
                success: false,
                msg: "Mobile or username already registered."
            });
        }

        /* ---------------- REFER CHECK ---------------- */
        let referByUser = null;
        if (refer_code) {
            referByUser = await user_module.findOne({ my_code: refer_code }).lean();
            if (!referByUser) {
                return res.status(400).json({
                    success: false,
                    msg: "Invalid refer code."
                });
            }
        }

        /* ---------------- SETTINGS ---------------- */
        const settings = await fix_values_module.findOne().lean();
        const welcome_bonus = settings?.welcome_bonus || 0;

        const pinNumber = Number(security_pin);
        const my_code = getUserRandomToken(8, true);
        const hashedPassword = await bcrypt.hash(password, 10);

        /* ---------------- CREATE USER ---------------- */
        const created = await user_module.create({
            user_name: username,
            mobile: mobileNum,
            password: hashedPassword,
            security_pin: pinNumber,
            refer_code: refer_code || undefined,
            my_code,
            wallet_balance: welcome_bonus
        });

        /* ---------------- ADMIN WALLET ---------------- */
        const adminData = await admin_module.findOneAndUpdate(
            { admin_type: 0 },
            { $inc: { wallet_amount: -welcome_bonus } },
            { new: true }
        );

        /* ---------------- REFER ENTRY ---------------- */
        if (referByUser) {
            await refer_details_module.create({
                refer_to: created._id,
                refer_by: referByUser._id,
                refer_code,
                bonus: welcome_bonus
            });
        }

        /* ---------------- WALLET HISTORY ---------------- */
        if (welcome_bonus > 0) {
            await wallet_trans_history_module.create({
                userDB_id: created._id,
                amount: welcome_bonus,
                transaction_type: 1,
                before_wallet: 0,
                transaction_note: 'User Welcome Bonus',
                amount_status: 6,
                admin_name: adminData?.username || '',
                admin_type: adminData?.admin_type === 0 ? 0 : 1,
                tx_request_number: getUserRandomToken()
            });

            await user_notification_module.create({
                userDB_id: created._id,
                title: "Welcome bonus",
                msg: `🎉 Welcome! You've received ₹${welcome_bonus} Welcome Bonus. 🍀`
            });
        }

        /* ---------------- RESPONSE ---------------- */
        return res.json({
            success: true,
            user_name: created.user_name,
            mobile: created.mobile,
            msg: "You are successfully registered."
        });

    } catch (error) {
        console.error("Error in apiUserRegistration:", error);
        return res.status(500).json({
            success: false,
            msg: error?.message || "Internal Server Error"
        });
    }
};



// middleware not used for JWT token
const apiUserStatus = async (req, res) => {
    try {
        let { app_key = "", env_type = "", userDB_id = "" } = req?.body || {};
        app_key = toStr(app_key);
        env_type = toStr(env_type);
        userDB_id = toStr(userDB_id);

        if (!app_key || !env_type || !userDB_id) {
            return res
                .status(400)
                .json({
                    success: false,
                    msg: 'All fields are required.'
                });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res
                .status(401)
                .json({ success: false, msg: 'Unauthorized request.' });
        }

        const user = await user_module
            .findById(userDB_id)
            .lean();
        if (!user) {
            return res
                .status(404)
                .json({
                    success: false,
                    msg: 'User ID is not valid.'
                });
        }

        const isActive =
            user.status > 0 &&
            user.betting_status === 1 &&
            user.wallet_balance > 0;

        return res.json({
            success: true,
            user_status: isActive,
            msg: 'Get User Status.'
        });
    } catch (error) {
        console.error('apiUserStatus error:', error);
        return res
            .status(500)
            .json({ success: false, msg: 'Internal Server Error' });
    }
};

// middleware not used for JWT token
const apiUserLogin = async (req, res) => {
    try {
        if (!process?.env?.JWT_SECRET) {
            return res.status(500).json({ success: false, msg: "JWT secret not found" });
        }
        let { app_key = "", env_type = "", mobile = "", password = "", device_id = "" } = req?.body || {};
        app_key = toStr(app_key);
        env_type = toStr(env_type);
        mobile = Number(toStr(mobile));
        inputPassword = toStr(password);
        device_id = toStr(device_id);


        // if (!app_key || !env_type || !mobile || !device_id) {
        if (!app_key || !env_type || !mobile) {
            return res
                .status(400)
                .json({ success: false, msg: 'All fields are required.' });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res
                .status(401)
                .json({ success: false, msg: 'Unauthorized request.' });
        }

        const mobileRegex = /^\d{10}$/;
        // const passwordRegex = /^.{8,}$/;
        if (!mobileRegex.test(mobile)) {
            return res
                .status(400)
                .json({ success: false, msg: 'Invalid mobile. Must be 10 digits.' });
        }
        // if (!passwordRegex.test(password)) {
        //     return res
        //         .status(400)
        //         .json({ success: false, msg: 'Password must be â‰¥8 characters.' });
        // }

        if (password.length < 6) {
            return res
                .status(400)
                .json({ success: false, msg: 'Password must be 6 characters.' });
        }

        const mobileNum = Number(mobile);
        const user = await user_module.findOne({ mobile: mobileNum });

        // console.log(`(((((((()))))) ~ mobileController.js:885 ~ apiUserLogin ~ user:`, user);

        if (!user) {
            return res.status(404).json({ success: false, msg: 'Mobile not found.' });
        }

        const {
            _id,
            user_name,
            betting_status,
            status,
            other_notification_status,
            main_game_notification_status,
            gali_disswar_game_notification_status,
            starline_game_notification_status,
        } = user;

        if (status === 0) {
            return res.json({ success: false, msg: 'Account blocked. Contact admin.' });
        }

        const hash = user.password;

        user.last_update = new Date()

        const match = await bcrypt.compare(inputPassword, hash);

        // console.log(`(((((((()))))) ~ mobileController.js:909 ~ apiUserLogin ~ match:`, match);
        if (!match) {
            return res.status(401).json({ success: false, msg: 'Invalid login details.' });
        }

        const settings = await contact_settings_module
            .findOne()
            .lean();

        const mobile_no = settings?.whatsapp_no || '';

        if (!mongoose.isValidObjectId(_id)) {
            return res.status(400).json({ success: false, msg: "Invalid ID" });
        }

        // await user_device_record_module.updateOne(
        //     { userDB_id: _id, device_id },
        //     { $set: { userDB_id: _id, device_id } },
        //     { upsert: true }
        // );

        // const unique_jwt_token = jwt.sign(
        //     { user: user._id },
        //     process?.env?.JWT_SECRET,
        // );

        const unique_jwt_token = jwt.sign(
            {
                user: user._id,
                device_id: device_id, // Add device identifier
            },
            process.env.JWT_SECRET,
            { expiresIn: "30d" }   // optional, but recommended
        );

        // user.unique_jwt_token = unique_jwt_token
        // 
        user.logout_status = 0;

        user.device_id = device_id;

        await user.save();

        return res.json({
            success: true,
            msg: 'Login successful.',
            unique_jwt_token,
            user_name,
            mobile: mobileNum.toString(),

            other_notification_status: `${other_notification_status}`,
            main_game_notification_status: `${main_game_notification_status}`,
            gali_disswar_game_notification_status: `${gali_disswar_game_notification_status}`,
            starline_game_notification_status: `${starline_game_notification_status}`,

            mobile_no: mobile_no.toString(),
            betting_status: betting_status.toString()
        });
    } catch (error) {
        console.error('Login Error:', error);
        return res
            .status(500)
            .json({ success: false, msg: 'Internal Server Error' });
    }
};


// Neon

// middleware & jwt token required 
const verifyMpin = async (req, res) => {
    try {

        if (!req.user) {
            return res.status(401).json({ status: false, message: "Unauthorized" });
        }

        const { security_pin } = req?.body;

        if (parseInt(security_pin) !== req.user.security_pin) {

            return res.status(401).json({ status: false, message: "M-pin not matched" });

        }

        // remove password/hash before sending
        const userData = req.user.toObject();
        delete userData.password;

        const deviceId = userData?.device_id;



        return res.status(200).json({
            success: true,
            message: "Mpin Verified, login successful",
            data: userData,
        });

    } catch (err) {
        console.error("Internal server error", err);
        return res.status(500).json({ status: false, message: "Internal Server Error" });
    }
};

// Middleware & jwt token required 
const forgetPasswordMpin = async (req, res) => {
  try {
    let { mobile = "", app_key = "", env_type = "" } = req.body || {};

    if (!app_key || !env_type || !mobile) {
      return res.status(400).json({
        success: false,
        msg: 'All fields are required.'
      });
    }

    if (!checkRequestAuth(app_key, env_type)) {
      return res.status(401).json({
        success: false,
        msg: 'Unauthorized request.'
      });
    }

    if (!/^\d{10}$/.test(mobile)) {
      return res.status(400).json({
        success: false,
        msg: 'Invalid mobile number.'
      });
    }

    const user = await user_module.findOne({ mobile });
    if (!user) {
      return res.status(404).json({
        success: false,
        msg: 'User not found.'
      });
    }

    // ✅ Generate OTP
    const otp = getOtp(mobile);

    // ✅ Store OTP (hashed) + expiry (5 minutes)
    user.otp = otp.toString(); // 🔐 ideally hash this
    user.otp_expiry = new Date(Date.now() + 5 * 60 * 1000);
    await user.save();

    // ✅ Send OTP
    if (otp !== 1234) {
      await sendMessage(mobile, otp.toString());
    }

    return res.json({
      success: true,
      msg: 'OTP sent successfully.',
      otp: otp
      // ❌ DO NOT SEND OTP IN PRODUCTION
    });

  } catch (err) {
    console.error(err);
    return res.status(500).json({
      success: false,
      msg: 'Internal Server Error'
    });
  }
};
const verifyForgetOtp = async (req, res) => {
  try {
    const { mobile = "", otp = "" } = req.body;

    if (!mobile || !otp) {
      return res.status(400).json({
        success: false,
        msg: 'Mobile and OTP are required'
      });
    }

    const user = await user_module.findOne({ mobile });
    if (!user || !user.otp) {
      return res.status(400).json({
        success: false,
        msg: 'OTP not found or expired'
      });
    }

    // ⏰ Check expiry
    if (new Date() > user.otp_expiry) {
      user.otp = null;
      user.otp_expiry = null;
      await user.save();

      return res.status(400).json({
        success: false,
        msg: 'OTP expired'
      });
    }

    // 🔐 Compare OTP
    if (user.otp !== otp.toString()) {
      return res.status(400).json({
        success: false,
        msg: 'Invalid OTP'
      });
    }

    // ✅ OTP verified – clear it
    user.otp = null;
    user.otp_expiry = null;
    await user.save();

    return res.json({
      success: true,
      msg: 'OTP verified successfully'
    });

  } catch (err) {
    console.error(err);
    return res.status(500).json({
      success: false,
      msg: 'Server error'
    });
  }
};


const changePasswordMpin = async (req, res) => {

    try {

        let { mobile = "", security_pin = "", password = "", app_key = "", env_type = "" } = req?.body || {};

        app_key = toStr(app_key);
        env_type = toStr(env_type);

        if (!app_key || !env_type || (!security_pin && !password)) {
            return res
                .status(400)
                .json({ success: false, msg: 'All fields are required.' });
        }
        if (password.length < 6) {
            return res
                .status(400)
                .json({ success: false, msg: 'Password must be 6 characters' });
        }



        if (!checkRequestAuth(app_key, env_type)) {
            return res
                .status(401)
                .json({ success: false, msg: 'Unauthorized request.' });
        }

        let userData;
        let message = "";

        if (security_pin) {

            userData = await user_module.findOneAndUpdate({ mobile }, { security_pin }, { new: true });
            message = "M-pin updated successfully.";

        }

        if (password) {

            password = await bcrypt.hash(password, 10);

            userData = await user_module.findOneAndUpdate({ mobile }, { password }, { new: true });
            message = "Password updated successfully.";
        }

        userData = userData.toObject();

        delete userData.password;


        if (!userData) {
            return res
                .status(401)
                .json({ success: false, msg: 'User not found.' });
        }

        // (omit sending OTP value in production)
        return res.json({ success: true, message, data: userData });

    } catch (err) {

        console.log(err);
        return res.status(500).json({ status: false, message: "Internal Server Error" });

    }

};

// middleware & jwt token required 
const checkToken = async (req, res) => {
    try {
        if (!req.user) {
            return res.status(401).json({ status: false, message: "Unauthorized" });
        }

        // remove password/hash before sending
        const userData = req.user.toObject();
        delete userData.password;

        return res.status(200).json({
            status: true,
            message: "Token Verified, Auto login successful",
            data: userData,
        });
    } catch (err) {
        console.error("Internal server error", err);
        return res.status(500).json({ status: false, message: "Internal Server Error" });

    }


};


// Neon

const apiChangePassword = async (req, res) => {
    try {
        let { old_pass = "", new_pass = "" } = req?.body || {};
        old_pass = toStr(old_pass);
        new_pass = toStr(new_pass);

        if (!old_pass || !new_pass) {
            return res
                .status(400)
                .json({ success: false, msg: 'Both old_pass and new_pass are required.' });
        }

        if (new_pass.length < 6) {
            return res
                .status(400)
                .json({ success: false, msg: 'Password must be 6 characters.' });
        }

        // let passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_]).{8,}$/;
        // if (!passwordRegex.test(new_pass)) {
        //     return res.status(400).json({
        //         success: false,
        //         msg: 'Password must include uppercase, lowercase, number, and special character'
        //     });
        // }

        const user = req?.user || null;
        if (!user?._id) {
            return res
                .status(404)
                .json({ success: false, msg: 'User not found.' });
        }

        const match = await bcrypt.compare(old_pass, user.password);
        if (!match) {
            return res
                .json({ success: false, msg: 'Old password does not match.' });
        }

        const hashed = await bcrypt.hash(new_pass, 10);
        await user_module.updateOne(
            { _id: user._id },
            { $set: { password: hashed } }
        );

        return res.json({
            success: true,
            msg: 'Password updated successfully.'
        });
    } catch (error) {
        console.error('Change Password Error:', error);
        return res
            .status(500)
            .json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiUpdatePin = async (req, res) => {
    try {
        let { mobile = "", security_pin = "" } = req?.body || {};
        const mobileStr = Number(toStr(mobile));
        const newPinStr = Number(toStr(security_pin));
        const userData = req.user

        if (!userData) {
            return res
                .status(401)
                .json({ success: false, msg: 'User not found.' });
        }

        if (!mobileStr || !newPinStr) {
            return res
                .status(400)
                .json({ success: false, msg: 'All fields are required.' });
        }

        const mobileRegex = /^\d{10}$/;
        const pinRegex = /^\d{4}$/;
        if (!mobileRegex.test(mobileStr)) {
            return res.status(400).json({
                success: false,
                msg: 'Invalid mobile number. Must be exactly 10 digits.'
            });
        }
        if (!pinRegex.test(newPinStr)) {
            return res.status(400).json({
                success: false,
                msg: 'Invalid new security pin. Must be exactly 4 digits.'
            });
        }

        if (userData.mobile !== mobileStr) {
            return res.json({
                success: false,
                msg: 'This mobile number is not registered.'
            });
        }

        const newPinNum = Number(newPinStr);
        userData.security_pin = newPinNum
        await userData.save()

        return res.json({
            success: true,
            msg: 'Pin successfully changed.'
        });
    } catch (error) {
        console.error('Error in apiForgotPin:', error);
        return res
            .status(500)
            .json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiForgotPin = async (req, res) => {
    try {
        let { mobile: mobileRaw = "", security_pin: pinRaw = "", Old_security_pin = "" } = req.body;

        const userData = req.user
        const mobileNum = Number(toStr(mobileRaw));
        const newPinNum = Number(toStr(pinRaw));
        const oldPinNum = Number(toStr(Old_security_pin));

        if (!userData) {
            return res
                .status(401)
                .json({ success: false, msg: 'User not found.' });
        }

        if (!mobileNum || !newPinNum) {
            return res
                .status(400)
                .json({ success: false, msg: 'All fields are required.' });
        }

        const mobileRegex = /^\d{10}$/;
        const pinRegex = /^\d{4}$/;

        if (!mobileRegex.test(mobileNum)) {
            return res
                .status(400)
                .json({ success: false, msg: 'Invalid mobile number. Must be exactly 10 digits.' });
        }
        if (!pinRegex.test(newPinNum)) {
            return res
                .status(400)
                .json({ success: false, msg: 'Invalid security pin. Must be exactly 4 digits.' });
        }

        if (userData.security_pin !== oldPinNum) {
            return res
                .status(400)
                .json({ success: false, msg: 'Invalid security pin. old pin dose not match' });
        }

        if (userData?.mobile !== mobileNum) {
            return res
                .status(401)
                .json({ success: false, msg: 'Incorrect mobile number.' });
        }

        userData.security_pin = newPinNum

        await userData.save()

        return res.json({ success: true, msg: 'Pin successfully changed.' });
    } catch (error) {
        console.error('Error in apiUpdatePin:', error);
        return res
            .status(500)
            .json({ success: false, msg: 'Internal Server Error' });
    }
};

// middleware not used for JWT token
const apiForgotPassword = async (req, res) => {
    try {
        let { app_key = "", env_type = "", mobile = "", new_pass = "" } = req?.body || {};
        app_key = toStr(app_key);
        env_type = toStr(env_type);
        mobile = Number(toStr(mobile));
        new_pass = toStr(new_pass);

        if (!app_key || !env_type || !mobile || !new_pass) {
            return res
                .status(400)
                .json({ success: false, msg: 'All fields are required.' });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res
                .status(401)
                .json({ success: false, msg: 'Unauthorized request.' });
        }

        const mobileRegex = /^\d{10}$/;
        // let passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_]).{8,}$/;

        if (!mobileRegex.test(mobile)) {
            return res.status(400).json({
                success: false,
                msg: 'Invalid mobile number. Must be exactly 10 digits.'
            });
        }

        // if (!passwordRegex.test(new_pass)) {
        //     return res.status(400).json({
        //         success: false,
        //         msg: 'Password must include uppercase, lowercase, number, and special character'
        //     });
        // }

        if (new_pass.length < 6) {
            return res.status(400).json({
                success: false,
                msg: 'Password length must be 6'
            });
        }

        const user = await user_module.findOne({ mobile: Number(mobile) }).lean();
        if (!user) {
            return res.json({
                success: false,
                msg: 'This mobile number is not registered.'
            });
        }

        const hashed = await bcrypt.hash(new_pass, 10);
        await user_module.updateOne(
            { _id: user._id },
            { $set: { password: hashed } }
        );

        return res.json({
            success: true,
            msg: 'Password successfully changed.'
        });

    } catch (error) {
        console.error('Error in apiForgotPassword:', error);
        return res
            .status(500)
            .json({ success: false, msg: 'Internal Server Error' });
    }
};

// middleware not used for JWT token
const apiCheckUserDeviceId = async (req, res) => {
    try {
        let { device_id = "", env_type = "", app_key = "" } = req?.body || {};
        env_type = toStr(env_type);
        app_key = toStr(app_key);
        const deviceIdNum = Number(device_id);

        if (!env_type || !app_key) {
            return res
                .status(400)
                .json({ success: false, msg: 'All fields are required.' });
        }
        if (!deviceIdNum) {
            return res
                .status(400)
                .json({ success: false, msg: 'device_id is required and must be numeric.' });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res
                .status(401)
                .json({ success: false, msg: 'Unauthorized request.' });
        }

        const deviceRecord = await user_device_record_module
            .findOne({ device_id: deviceIdNum })
            .lean();
        if (!deviceRecord) {
            return res
                .status(404)
                .json({ success: false, msg: 'Device not found.' });
        }

        const user = await user_module
            .findById(deviceRecord.userDB_id)
            .lean();
        if (!user) {
            return res
                .status(404)
                .json({ success: false, msg: 'User not found.' });
        }

        if (user.status === 0) {
            return res.json({
                success: false,
                msg: 'Account is blocked by admin. Please contact the admin.',
            });
        }

        const { _id, user_name, username, mobile } = user;
        return res.json({
            success: true,
            msg: 'Successful.',
            _id,
            user_name,
            username,
            mobile,
        });

    } catch (error) {
        console.error('Device ID Check Error:', error);
        return res
            .status(500)
            .json({ success: false, msg: 'Internal Server Error' });
    }
};

// middleware not used for JWT token
const apiForgetCheckmobile = async (req, res) => {
    try {
        let { app_key = "", env_type = "", mobile = "" } = req?.body || {};
        app_key = toStr(app_key);
        env_type = toStr(env_type);
        mobile = Number(toStr(mobile));

        if (!app_key || !env_type || !mobile) {
            return res
                .status(400)
                .json({ success: false, msg: 'All fields are required.' });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res
                .status(401)
                .json({ success: false, msg: 'Unauthorized request.' });
        }

        const mobileRegex = /^\d{10}$/;
        if (!mobileRegex.test(mobile)) {
            return res.status(400).json({
                success: false,
                msg: 'Invalid mobile number. Must be exactly 10 digits.'
            });
        }

        const user = await user_module
            .findOne({ mobile: Number(mobile) })
            .lean();
        if (!user) {
            return res.json({
                success: false,
                msg: 'Mobile number is not registered.'
            });
        }

        const otp = await getOtp(mobile);

        if (otp !== 1234) {
            const message = `${otp} use this OTP to change your password. Please do not share it with anyone.`;
            // await sendMessage(mobile, message);
        }

        return res.json({
            success: true,
            otp,
            msg: 'Mobile number is registered. Try Login.'
        });
    } catch (error) {
        console.error('Error in apiForgetCheckmobile:', error);
        return res
            .status(500)
            .json({ success: false, msg: 'Internal Server Error' });
    }
};

// middleware not used for JWT token
const apiAdminBankDetails = async (req, res) => {
    try {
        let { app_key = "", env_type = "" } = req?.body || {};
        app_key = toStr(app_key);
        env_type = toStr(env_type);
        if (!app_key || !env_type) {
            return res.status(404).json({ success: false, msg: 'All fields are required.' });
        }

        if (checkRequestAuth(app_key, env_type) === 0) {
            return res.status(403).json({ success: false, msg: 'Unauthorized request' });
        }

        let bankDetails = await admin_bank_detail_module.findOne().lean();
        bankDetails.account_number = bankDetails?.account_number?.toString() || ''
        bankDetails.ifsc_code = bankDetails?.ifsc_code?.toString() || ''
        bankDetails.ac_holder_name = bankDetails?.ac_holder_name?.toString() || ''
        bankDetails.status = bankDetails?.status?.toString() || ''
        bankDetails.insert_date = formatDateToDDMMYYYY(bankDetails?.insert_date)

        if (bankDetails) {
            return res.json({
                success: true,
                bank_details: [bankDetails],
                msg: 'Admin Bank Detail',
            });
        } else {
            return res.json({
                success: false,
                bank_details: [],
                msg: 'Data Not Found',
            });
        }

    } catch (error) {
        console.error('Error in apiAdminBankDetails:', error);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

// middleware not used for JWT token
const apiGetContactDetails = async (req, res) => {
    try {
        let { app_key = "", env_type = "" } = req.body || {};

        app_key = toStr(app_key).trim();
        env_type = toStr(env_type).trim();

        if (!app_key || !env_type) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        if (checkRequestAuth(app_key, env_type) === 0) {
            return res.status(401).json({ success: false, msg: 'Unauthorized request' });
        }

        const contacts = await contact_settings_module.findOne().lean();

        if (!contacts) {
            return res.status(404).json({ success: false, msg: 'No Contact Settings Found' });
        }

        const {
            mobile = "Null",
            whatsapp_no = "Null",
            email = "Null",
            facebook = "Null",
            youtube = "Null",
            instagram = "Null",
            telegram_username = "Null"
        } = contacts;

        let cleanedTelegram = toStr(telegram_username).trim();
        if (cleanedTelegram.startsWith("@")) {
            cleanedTelegram = cleanedTelegram.slice(1); // Remove '@'
        }
        const telegram_link = cleanedTelegram !== "Null" ? `https://telegram.me/${cleanedTelegram}` : "Null";

        if (!email || !mobile) {
            return res.status(404).json({ success: false, msg: 'Contact email & mobile. No. Not Available' });
        }

        return res.json({
            success: true,
            message: 'Support data fetched successfully',
            supportData: {
                mobile: toStr(mobile),
                whatsapp_no: toStr(whatsapp_no),
                email,
                facebook,
                youtube,
                instagram,
                telegram_link
            }
        });

    } catch (err) {
        console.error('apiGetContactDetails error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

// middleware not used for JWT token
const apiGetSliderImages = async (req, res) => {
    try {
        const baseUrl = process?.env?.BASE_URL;
        if (!baseUrl) {
            return res.status(500).json({ success: false, msg: "Base URL not set" });
        }
        let { app_key = '', env_type = '' } = req?.body || {};
        app_key = toStr(app_key);
        env_type = toStr(env_type);

        if (!app_key || !env_type) {
            return res.status(400).json({
                success: false,
                msg: 'All fields are required.',
            });
        }

        if (checkRequestAuth(app_key, env_type) !== 0) {
            const sliders = await slider_images_module
                .find({ status: 1 })
                .sort({ display_order: 1 })
                .lean();

            if (!sliders) {
                return res.json({
                    success: false,
                    sliderdata: [],
                    msg: 'Data Not Available',
                });
            }

            const result = sliders.map(slide => ({
                image_id: slide._id,
                slider_image: `${baseUrl}/uploads/slider-images/${slide.filename?.toString()}`,
            }));

            if (result.length > 0) {
                return res.json({
                    success: true,
                    sliderdata: result,
                    msg: 'Slider Images Data',
                });
            } else {
                return res.json({
                    success: false.valueOf,
                    sliderdata: [],
                    msg: 'Data Not Available',
                });
            }
        } else {
            return res.status(401).json({
                success: false,
                msg: 'Unauthorized request',
            });
        }
    } catch (error) {
        console.error('apiGetSliderImages Error:', error);
        return res.status(500).json({
            success: false,
            msg: 'Internal Server Error',
        });
    }
};

const apiAddMoneyViaUpi = async (req, res) => {
    try {
        const {
            amount = 0,
            txn_ref = '',
            user_id = '',
            upigpay = '',
            upiphonepe = '',
            otherupi = '',
            paymentGateway = ''
        } = req.body || {};

        console.log("req -", req.body)
        // console.log("user-", req?.user)
        const userDB_id = req.user || user_id
        if (!userDB_id || userDB_id === "" || !mongoose.Types.ObjectId.isValid(userDB_id)) {
            return res.status(400).json({
                success: false,
                message: "Invalid user ID"
            });
        }


        const user = await user_module.findById((userDB_id));

        if (!user) {
            return res.status(404).json({ status: false, msg: "User not found" });
        }


        // if (!req?.file || !req?.file?.filename) {
        //     return res.status(400).json({ status: false, msg: "Payment receipt is required" });
        // }


        const request_number = getUserRandomToken();
        const amt = Number(amount);

        const previousTx = await wallet_trans_history_module.find({
            userDB_id,
            amount_status: { $in: [1, 19] }
        });

        // console.log(`(((((((()))))) ~ mobileController.js:1786 ~ apiAddMoneyViaUpi ~ previousTx:`, previousTx);

        if (previousTx.length === 0) {

            // console.log("enter in the previous block")
            const referData = await refer_details_module.findOne({ refer_to: userDB_id })
                .populate("refer_to")
                .populate("refer_by");

            // console.log(`(((((((()))))) ~ mobileController.js:1794 ~ apiAddMoneyViaUpi ~ referData:`, referData);
            if (referData && referData.refer_by) {
                // console.log("enter in the referData block")

                const referUser = referData.refer_by;
                const setting = await fix_values_module.findOne();

                // console.log(`(((((((()))))) ~ mobileController.js:1801 ~ apiAddMoneyViaUpi ~ setting:`, setting);
                if (setting) {
                    const bonusPercent = referUser.is_agent ? setting.agent_refer_bonus : setting.user_refer_bonus;
                    const bonus = (amt * bonusPercent) / 100;
                    referUser.wallet_balance += bonus;
                    await referUser.save();

                    referData.bonus += bonus;
                    await referData.save();

                    await wallet_trans_history_module.create({
                        userDB_id: referUser._id,
                        amount: bonus,
                        transaction_type: 1,
                        transaction_note: "User Refer Bonus",
                        amount_status: 6,
                        tx_request_number: getUserRandomToken(),
                    });
                }
            }
        }

        // if (Number(upigpay) === 1 || Number(upiphonepe) === 1) {
        if (Number(paymentGateway) === 1) {
            const new_wallet_amt = user.wallet_balance + amt;
            user.wallet_balance = new_wallet_amt;
            await user.save();

            await wallet_trans_history_module.create({
                userDB_id,
                amount: amt,
                transaction_type: 1,
                transaction_note: `Points added via UPI Tx ID ${txn_ref}`,
                amount_status: 19,
                tx_request_number: request_number,
                txn_ref,
            });

            // âœ… Insert auto-deposit
            await add_funds_module.create({
                userDB_id,
                amount: amt,
                // file_path: req?.file?.destination,
                // fund_payment_receipt: req?.file?.filename,
                fund_status: 0,
                tx_request_number: request_number,
                txn_ref,
                payment_method,
                deposit_type: 1,
            });

            return res.json({ success: true, msg: "Points Added Successfully, Please Wait for admin Approval" });

        } else {
            // Manual deposit: insert auto_deposit for admin approval

            const payment_method = Number(upigpay) === 1 ? "Google Pay" : Number(upiphonepe) === 1 ? "Phone Pe" : otherupi;

            await add_funds_module.create({
                userDB_id,
                amount: amt,
                // file_path: req?.file?.destination,
                // fund_payment_receipt: req?.file?.filename,
                tx_request_number: request_number,
                txn_ref,
                payment_method: payment_method,
                fund_status: 0,
                deposit_type: 0,
            });

            return res.json({
                success: true,
                msg: "Points Added Successfully. Please Wait for admin Approval"
            });
        }
    } catch (err) {
        console.error("apiAddMoneyViaUpi Error:", err);
        return res.status(500).json({ success: false, msg: "Server Error" });
    }
};



const apiGetCurrentDate = async (req, res) => {
    try {
        // let { gameDB_id = "" } = req?.body || {};
        // gameDB_id = toStr(gameDB_id);

        const data_json = {};

        const userData = req?.user || null;

        if (!userData) {
            return res.status(401).json({ success: false, msg: 'User not found' });
        }

        data_json.wallet_amt = (userData.wallet_balance)?.toString() || '';

        const settings = await fix_values_module.findOne().lean();
        if (settings) {
            data_json.min_bid_amount = (settings.min_bid_amount).toString() || '';
            data_json.max_bid_amount = (settings.max_bid_amount)?.toString() || '';
            data_json.min_deposite = (settings.min_deposite)?.toString() || '';
            data_json.max_deposite = (settings.max_deposite)?.toString() || '';
            data_json.min_withdrawal = (settings.min_withdrawal)?.toString() || '';
            data_json.max_withdrawal = (settings.max_withdrawal)?.toString() || '';
            data_json.withdraw_open_time = get12HoursTimeFromISO(settings.withdraw_open_time);
            data_json.withdraw_close_time = get12HoursTimeFromISO(settings.withdraw_close_time);
            data_json.min_transfer = (settings.min_transfer)?.toString() || '';
            data_json.max_transfer = (settings.max_transfer)?.toString() || '';
            data_json.withdrawLimit = (settings.withdrawLimit)?.toString() || '';
        } else {
            return res.status(500).json({ success: false, msg: 'Settings not found' });
        }

        const now = new Date();
        data_json.date = now.toLocaleDateString('en-GB', {
            weekday: 'short',
            day: '2-digit',
            month: 'short',
            year: 'numeric'
        });
        data_json.new_date = now.toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' });

        // const game = await games_module.findById(gameDB_id).lean();
        let open_sec = 0;
        let close_sec = 0;

        // if (game) {
        //     const currentTime = new Date();
        //     const openTime = new Date(currentTime.toDateString() + ' ' + game.open_time);
        //     const closeTime = new Date(currentTime.toDateString() + ' ' + game.close_time);

        //     open_sec = Math.floor((openTime - currentTime) / 1000) - 60;
        //     close_sec = Math.floor((closeTime - currentTime) / 1000) - 60;

        //     data_json.open_duration = Math.max(open_sec, 0) * 1000;
        //     data_json.close_duration = Math.max(close_sec, 0) * 1000;
        // }

        const content = await content_rules_module.find();
        // console.log("🚀 ~ apiGetCurrentDate ~ content:", content)

        if (content) {
            data_json.content_rules = content[0];

        } else {
            data_json.content_rules = {};
        }

        console.log("🚀 ~ apiGetCurrentDate ~ userData._id:", userData._id)

        // const checkWithdrawRequest = await withdraw_fund_request_module.find({
        //     userDB_id: userData._id
        // }).lean();



        // console.log(checkWithdrawRequest.length, "🚀 ~ apiGetCurrentDate ~ checkWithdrawRequest:", checkWithdrawRequest)

        // if (!checkWithdrawRequest || checkWithdrawRequest == null) {
        //     data_json.withdraw_request_status = true;
        //     data_json.withdraw_request_msg = "No prevoise withdraw records found !";

        // } else if (checkWithdrawRequest && checkWithdrawRequest.fund_status === 0) {

        //     data_json.withdraw_request_status = false;
        //     data_json.withdraw_request_msg = "Your previous withdraw request is still pending. You cannot make a new withdraw request until the previous one is processed.";
        // }
        // else {
        //     data_json.withdraw_request_status = false;
        //     data_json.withdraw_request_msg = "You have already made a withdraw request today. You can make a new withdraw request on next day.";
        // }

        const checkWithdrawRequest = await withdraw_fund_request_module.find({
            userDB_id: userData._id
        }).lean();

        // console.log(checkWithdrawRequest.length, "🚀 ~ apiGetCurrentDate ~ checkWithdrawRequest:", checkWithdrawRequest);

        // Get withdrawal limit from settings

        const withdrawLimit = settings?.withdrawLimit || 0; // Default to 0 if not found
        console.log("🚀 ~ apiGetCurrentDate ~ withdrawLimit:", withdrawLimit)

        // Get today's date in IST for comparison
        const todayIST = moment_timeZone().tz('Asia/Kolkata').startOf('day');
        const todayEndIST = moment_timeZone().tz('Asia/Kolkata').endOf('day');
        console.log("🚀 ~ apiGetCurrentDate ~ todayEndIST:", todayEndIST)

        // Check if there's any pending request (fund_status === 0) from any date
        const hasPendingRequest = checkWithdrawRequest.some(request => request.fund_status === 0);

        if (hasPendingRequest) {
            // Case 1: There's at least one pending request
            data_json.withdraw_request_status = false;
            data_json.withdraw_request_msg = "Your previous withdraw request is still pending. You cannot make a new withdraw request until the previous one is processed.";
        } else {
            // Case 2: No pending requests, check today's withdrawal count against limit

            // Filter requests from today only
            const todaysRequests = checkWithdrawRequest.filter(request => {
                const requestDate = moment_timeZone(request.insert_date).tz('Asia/Kolkata');
                return requestDate.isBetween(todayIST, todayEndIST);
            });

            console.log("🚀 ~ Todays withdrawal requests count:", todaysRequests.length);
            console.log("🚀 ~ Withdrawal limit:", withdrawLimit);

            if (todaysRequests.length >= withdrawLimit) {
                // Case 2a: User has reached or exceeded today's withdrawal limit
                data_json.withdraw_request_status = false;
                data_json.withdraw_request_msg = `You have already made ${todaysRequests.length} withdraw request(s) today. Maximum ${withdrawLimit} withdraw request(s) are allowed per day. You can make a new withdraw request tomorrow.`;
            } else {
                // Case 2b: User can make more withdrawals today
                data_json.withdraw_request_status = true;
                data_json.withdraw_request_msg = `You can make withdraw request. ${withdrawLimit - todaysRequests.length} request(s) remaining for today.`;
            }
        }

        // Additional info for debugging
        data_json.withdraw_limit_info = {
            daily_limit: withdrawLimit,
            pending_requests: checkWithdrawRequest.filter(req => req.fund_status === 0).length,
            todays_requests: checkWithdrawRequest.filter(request => {
                const requestDate = moment_timeZone(request.insert_date).tz('Asia/Kolkata');
                return requestDate.isBetween(todayIST, todayEndIST);
            }).length
        };






        data_json.success = true;
        return res.json(data_json);
    } catch (error) {
        console.error('apiGetCurrentDate Error:', error);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiGetAutoDepositList = async (req, res) => {
    try {
        const { status = '' } = req.body;
        const userData = req.user;

        if (!userData) return res.status(404).json({ success: false, msg: 'User not found' });

        const filter = status === ''
            ? { userDB_id: userData._id }
            : { userDB_id: userData._id, fund_status: Number(status) };

        result = await add_funds_module.find(filter).sort({ _id: -1 }).lean();

        if (result.length > 0) {
            result = result.map(v => ({
                ...v,
                amount: String(v.amount ?? ''),
                fund_status: String(v.fund_status ?? ''),
                deposit_type: String(v.deposit_type ?? ''),
                tx_request_number: v?.tx_request_number?.toUpperCase(),
                insert_date: v.insert_date ? formatDateToDDMMYYYY(v.insert_date) + " , " + get12HoursTimeFromISO(v.insert_date)
                    : "N/A",
            }));
        }

        res.json({
            msg: 'Success',
            success: true,
            result
        });
    } catch (error) {
        console.error(error);
        res.status(500).json({
            msg: 'Server Error',
            success: false
        });
    }
};

const apidepositwithdrawHistoryData = async (req, res) => {
    try {
        const baseUrl = process.env.BASE_URL;
        if (!baseUrl) {
            return res.status(500).json({ success: false, msg: "Base URL not set" });
        }

        const userData = req?.user;
        if (!userData?._id) {
            return res.status(401).json({ success: false, msg: 'User not found' });
        }

        // ========== Withdraw History ==========
        const withdrawData = await withdraw_fund_request_module
            .find({ userDB_id: userData._id })
            .sort({ _id: -1 })
            .lean();

        const formattedWithdrawData = withdrawData.map(entry => {
            const receiptUrl = entry.fund_payment_receipt
                ? `${baseUrl}/file/uploads/images/${entry.fund_payment_receipt}`
                : '';

            return {
                request_amount: `${entry.amount || ''}`,
                tx_request_number: `${entry.tx_request_number || ''}`,
                request_status: `${entry.request_status || ''}`,
                payment_method: `${entry.payment_method || ''}`,
                bank_name: entry.bank_name || '',
                branch_address: entry.branch_address || '',
                ac_holder_name: entry.ac_holder_name || '',
                ac_number: `${entry.ac_number || ''}`,
                ifsc_code: entry.ifsc_code || '',
                paytm_number: `${entry.paytm_number || ''}`,
                google_pay_number: `${entry.google_pay_number || ''}`,
                phone_pay_number: `${entry.phone_pay_number || ''}`,
                remark: entry.remark || '',
                payment_receipt: receiptUrl,
                insert_date: entry.insert_date
                    ? `${formatDateToDDMMYYYY(entry.insert_date)}, ${get12HoursTimeFromISO(entry.insert_date)}`
                    : ''
            };
        });

        // ========== Deposit History ==========
        const depositData = await wallet_trans_history_module
            .find({ userDB_id: userData._id, transaction_type: 1 })
            .sort({ _id: -1 })
            .lean();

        const formattedDepositData = depositData.map(tx => ({
            amount: `${tx.amount || ''}`,
            transaction_type: `${tx.transaction_type || ''}`,
            amount_status: `${tx.amount_status || ''}`,
            transaction_note: tx.transaction_note || '',
            insert_date: tx.insert_date
                ? `${formatDateToDDMMYYYY(tx.insert_date)}, ${get12HoursTimeFromISO(tx.insert_date)}`
                : ''
        }));

        // ========== Wallet Balance ==========
        const wallet = await user_module.findById(userData._id).lean();
        const walletBalance = wallet?.wallet_balance ?? '';

        // ========== Final Response ==========
        const success = formattedWithdrawData.length > 0 || formattedDepositData.length > 0;
        const msg = success ? 'Transaction Data' : 'Withdraw Transaction Data Not Available';

        return res.json({
            success,
            withdrawdata: formattedWithdrawData.length ? formattedWithdrawData : [],
            Depositdata: formattedDepositData.length ? formattedDepositData : [],
            msg,
            wallet_amt: walletBalance
        });

    } catch (error) {
        console.error("apidepositwithdrawHistoryData Error:", error);
        return res.status(500).json({ success: false, msg: 'Server error' });
    }
};



const apiAddUserBankDetails = async (req, res) => {
    try {
        // ✅ extract user from auth middleware or unique_jwt_token in body
        let userData = req?.user || null;

        if (!userData || !userData._id) {
            return res.status(401).json({ success: false, msg: "User not found" });
        }

        function hasNumber(myString) {
            return /\d/.test(myString);
        }

        // ✅ destructure body
        let {
            bank_name = "",
            branch_address = "",
            ac_holder_name = "",
            ac_number = "",
            ifsc_code = ""
        } = req?.body || {};

        // ✅ sanitize (REMOVE .toLowerCase() from ifsc_code)
        bank_name = toStr(bank_name).trim();
        branch_address = toStr(branch_address).trim();
        ac_holder_name = toStr(ac_holder_name).trim();
        ac_number = toStr(ac_number).trim();
        ifsc_code = toStr(ifsc_code).trim(); // ← Remove .toLowerCase() here

        // ✅ validation
        if (!bank_name || !ac_holder_name || !ac_number || !ifsc_code) {
            return res.status(400).json({
                success: false,
                msg: "All fields (bank_name, ac_holder_name, ac_number, ifsc_code) are required"
            });
        }

        // ✅ Validate format BEFORE creating payload
        if (ifsc_code !== ifsc_code.toUpperCase() || (/[^0-9]/.test(ac_number)) || hasNumber(ac_holder_name)) {
            console.log("IFSC case check:", ifsc_code !== ifsc_code.toUpperCase())
            console.log("AC number numeric check:", /[^0-9]/.test(ac_number))
            console.log("AC holder has number:", hasNumber(ac_holder_name))
            return res.status(400).json({
                success: false,
                msg: "Check details again(ifsc code must be capital, account number must be numeric and holder name can't contains numbers)"
            });
        }

        // ✅ check if same bank details exist for another user
        const isAlreadyExistingBank = await user_bank_details_module.findOne({
            ac_number,
            ifsc_code,
            userDB_id: { $ne: userData._id }
        });

        if (isAlreadyExistingBank) {
            return res.status(409).json({
                success: false,
                msg: "Bank details already exist for another user"
            });
        }

        // ✅ payload for DB (now ifsc_code is already in uppercase)
        const userBankData = {
            bank_name: capitalizeWords(bank_name),
            branch_address,
            ac_holder_name: capitalizeWords(ac_holder_name),
            ac_number,
            ifsc_code, // This will be in uppercase now
            userDB_id: userData._id
        };
        console.log("🚀 ~ userBankData:", userBankData);

        // ✅ check if this user already has bank details
        const existingRecord = await user_bank_details_module.findOne({
            userDB_id: userData._id
        });

        if (existingRecord) {
            existingRecord.bank_name = userBankData.bank_name;
            existingRecord.branch_address = userBankData.branch_address;
            existingRecord.ac_holder_name = userBankData.ac_holder_name;
            existingRecord.ac_number = userBankData.ac_number;
            existingRecord.ifsc_code = userBankData.ifsc_code;

            await existingRecord.save();

            return res.json({
                success: true,
                msg: "Bank details updated successfully",
                data: existingRecord
            });
        }

        // ✅ create if not exists
        const newBank = await user_bank_details_module.create(userBankData);

        return res.json({
            success: true,
            bank_id: newBank._id,
            msg: "Bank details registered successfully"
        });

    } catch (error) {
        console.error("❌ Error in apiAddUserBankDetails:", error);
        return res.status(500).json({
            success: false,
            msg: "Internal Server Error",
            error: error.message
        });
    }
};




const apiUserBankDetails = async (req, res) => {
    try {
        const userData = req?.user || null;

        if (!userData || !userData._id) {
            return res.status(401).json({ success: false, msg: 'User not found' });
        }

        // let bankDetails = await user_bank_details_module.find({ userDB_id: userData._id }).lean();
        let bankDetailsArr = await user_bank_details_module.find({ userDB_id: userData._id }).lean();
        if (bankDetailsArr.length == 0) {
            return res.status(404).json({
                success: false,
                msg: "No bank details found"
            });
        }
        console.log("bankUserDataArr", bankDetailsArr)
        let bankDetails = bankDetailsArr[0];
        bankDetails.ac_number = bankDetails?.ac_number?.toString()
        bankDetails.paytm_number = bankDetails?.paytm_number?.toString()
        bankDetails.google_pay_number = bankDetails?.google_pay_number?.toString()
        bankDetails.phone_pay_number = bankDetails?.phone_pay_number?.toString()
        // bankDetails[0].ac_number = bankDetails[0]?.ac_number?.toString()
        // bankDetails[0].paytm_number = bankDetails[0]?.paytm_number?.toString()
        // bankDetails[0].google_pay_number = bankDetails[0]?.google_pay_number?.toString()
        // bankDetails[0].phone_pay_number = bankDetails[0]?.phone_pay_number?.toString()

        return res.json({
            success: true,
            bank_details: bankDetails,
            msg: 'User Bank Detail',
        });

    } catch (error) {
        console.error('Error in apiUserBankDetails:', error);
        return res.status(500).json({ success: false, msg: 'Internal Server ErrorIIII' });
    }
};


const apiWalletTransactionHistory = async (req, res) => {
    try {
        const { page = 1, limit = 10 } = req?.body;
        console.log("🚀 ~ apiWalletTransactionHistory ~ req?.user:", req?.user)

        const skip = (Number(page) - 1) * Number(limit);

        const userData = req?.user || null;
        if (!userData || !userData._id) {
            return res.status(401).json({ success: false, msg: 'User not found' });
        }

        // Total count query
        const totalTransactionsCount = await wallet_trans_history_module.countDocuments({
            userDB_id: userData._id,
            $or: [
                { transaction_type: 1 },
                { transaction_type: 2 },
                { transaction_note: "Amount Withdrawn By Admin" },
                { transaction_note: "Amount Withdraw" }
            ]
        });

        // Fetch transactions with PROPER sorting for bulk transactions
        let allTransactions = await wallet_trans_history_module.find({
            userDB_id: userData._id,
            $or: [
                { transaction_type: 1 },
                { transaction_type: 2 },
                { transaction_note: "Amount Withdrawn By Admin" },
                { transaction_note: "Amount Withdraw" }
            ]
        })
            .sort({
                insert_date: -1,    // First by date (newest first)
                _id: -1             // Then by _id for transactions with same timestamp
            })
            .skip(skip)
            .limit(Number(limit))
            .lean();

        console.log("🚀 ~ apiWalletTransactionHistory ~ totalTransactionsCount:", totalTransactionsCount)

        // Format transactions
        const formatTx = (txList) => txList.map((tx) => {
            return {
                tx_request_number: tx.tx_request_number,
                bid_txn_number: tx.bid_tx_id,
                _id: tx._id,
                main_gameDB_id: tx.main_gameDB_id || '',
                starline_gameDB_id: tx.starline_gameDB_id || '',
                jackpot_gameDB_id: tx.jackpot_gameDB_id || '',
                amount: tx.amount?.toString() || '',
                transaction_type: tx.transaction_type?.toString() || '',
                transaction_note: tx.transaction_note,
                transfer_note: tx.transfer_note || '',
                amount_status: tx.amount_status?.toString() || '',
                insert_date: formatDateToDDMMYYYY(tx.insert_date) + "," + get12HoursTimeFromISO(tx.insert_date),
                previous_balance: tx?.before_wallet ? tx?.before_wallet.toString() : "0",
                updated_balance: tx.transaction_type == 1 ?
                    (tx?.before_wallet + tx.amount).toString() :
                    (tx?.before_wallet - tx.amount).toString(),
            };
        });

        let data_json = {
            total_count: totalTransactionsCount,
            wallet_amt: userData.wallet_balance?.toString() || '',
            transaction_history: formatTx(allTransactions),
            msg: allTransactions.length > 0 ? 'Wallet Transaction History' : 'Wallet Transaction History Data Not Available',
            success: allTransactions.length > 0,
            current_page: Number(page),
            total_pages: Math.ceil(totalTransactionsCount / Number(limit))
        };

        // Add additional settings data
        const settings = await fix_values_module.findOne().lean();
        if (settings) {
            const { withdraw_open_time, withdraw_close_time } = settings;
            data_json.withdraw_open_time = get12HoursTimeFromISO(withdraw_open_time);
            data_json.withdraw_close_time = get12HoursTimeFromISO(withdraw_close_time);
        }

        const deviceLimit = process.env.DEVICE_LIMIT;
        if (deviceLimit) {
            const deviceResult = await user_device_record_module.find({ _id: userData._id }).limit(deviceLimit).lean();
            data_json.device_result = deviceResult;
        }

        res.json(data_json);
    } catch (error) {
        console.error('Error in apiWalletTransactionHistory:', error);
        res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

// const apiPassbookBidDataInfo = async (req, res) => {
//     try {
//         const { bidTxnId } = req.body;

//         if (!bidTxnId) {
//             console.log("bid txn id not found");
//             return res.status(404).json({ success: false, msg: "Bid txn id not found !" })
//         }


//         const bidData = await bid_history_module.findOne({ bid_tx_id: bidTxnId });
//         console.log("bid data passbook", bidData)

//         if (!bidData) {
//             console.log("bidData", bidData)
//             return res.status(404).json({ success: false, msg: "Bid data not found" });
//         }

//         const bidInfo = {
//             Type: bidData?.session,
//             providerName: bidData?.game_name,
//             gameType: bidData?.pana,
//             bixTxnId: bidData?.bid_tx_id,
//             bidAmount: bidData?.points,
//             DataTime: bidData?.insert_date,
//             status: bidData?.pay_status == 0 ? "Pending" : bidData?.pay_status == 1 ? "Win" : "Lose"
//         }

//         return res.status(200).json({ success: true, msg: "Bid data found successfully", bidInfo });



//     } catch (err) {
//         console.log("🚀 ~ apiPassbookBidDataInfo ~ err:", err)
//     }
// }

const apiPassbookBidDataInfo = async (req, res) => {
    try {
        const { bidTxnId } = req.body;

        if (!bidTxnId) {
            return res.status(400).json({ success: false, msg: "Bid txn id not found !" });
        }

        let bidData = {};
        let market = '';

        if (req?.body?.main_gameDB_id) {
            market = "Main game";
            bidData = await bid_history_module.findOne({ bid_tx_id: bidTxnId });
        }
        else if (req?.body?.starline_gameDB_id) {
            market = "Starline game";
            bidData = await starline_bid_history_module.findOne({ bid_tx_id: bidTxnId });
        }
        else if (req?.body?.jackpot_gameDB_id) {
            market = "Jackpot game";
            bidData = await gali_disswar_bid_history_module.findOne({ bid_tx_id: bidTxnId });
        }
        else {
            return res.status(404).json({ success: false, msg: "Bid data not found" });
        }



        if (!bidData) {
            return res.status(404).json({ success: false, msg: "Bid data not found" });
        }

        // === Format Date & Time (India Time - IST) ===
        const date = new Date(bidData.insert_date);
        const formattedDate = date.toLocaleDateString('en-GB', {
            day: '2-digit',
            month: 'short',
            year: 'numeric'
        }).replace(/ /g, ' '); // 19 Nov 2025

        const formattedTime = date.toLocaleTimeString('en-US', {
            hour: '2-digit',
            minute: '2-digit',
            hour12: true
        }).replace(/AM|PM/i, (match) => match.toUpperCase()); // 11:34 AM

        const niceDateTime = `${formattedDate}, ${formattedTime}`; // 19 Nov 2025, 11:34 AM

        // === Determine Win/Lose/Pending ===
        let status = "Pending";
        if (bidData.pay_status === 1) status = "Win";
        else if (bidData.pay_status === 2) status = "Lose";

        const bidInfo = {
            Type: bidData.session,                    // Open or Close
            providerName: bidData.game_name,
            market,         // KALYAN, MILAN DAY, Gali, 8:30 PM etc.
            gameType: bidData.pana,
            digit: bidData.closedigits ? `${bidData.digits}-${bidData.closedigits}` : bidData.digits,                    // Jodi Digit, Single Digit, etc.
            bixTxnId: bidData.bid_tx_id,
            bidAmount: bidData.points,
            DataTime: niceDateTime,                    // ← Clean & beautiful date
            status: status
        };

        return res.status(200).json({
            success: true,
            msg: "Bid data found successfully",
            bidInfo
        });

    } catch (err) {
        console.log("🚀 ~ apiPassbookBidDataInfo ~ err:", err);
        return res.status(500).json({ success: false, msg: "Server error" });
    }
};


const apiGetDashboardData = async (req, res) => {
    try {
        const userData = req.user;
        if (!userData || !userData._id) {
            return res.status(401).json({ success: false, msg: 'User not found' });
        }

        userData.last_update = moment_timeZone().tz('Asia/Kolkata').toDate();
        await userData.save();

        const appData = await app_link_module.findOne().lean();
        if (!appData) {
            return res.status(404).json({ success: false, msg: 'App link not found' });
        }

        const data_json = {
            app_link: appData?.app_link || '',
            share_msg: appData?.content || '',
        };

        const settings = await fix_values_module.findOne().lean();
        console.log("🚀 ~ apiGetDashboardData ~ settings:", settings)

        if (!settings) {
            return res.status(404).json({ success: false, msg: 'Settings not found' });
        }

        const now = moment_timeZone().tz('Asia/Kolkata');
        const today = now.format('YYYY-MM-DD');

        // FIXED: Proper time parsing with date context
        const openCompare = moment_timeZone.tz(`${today} ${settings.withdraw_open_time}`, 'YYYY-MM-DD HH:mm', 'Asia/Kolkata').toDate();
        const closeCompare = moment_timeZone.tz(`${today} ${settings.withdraw_close_time}`, 'YYYY-MM-DD HH:mm', 'Asia/Kolkata').toDate();

        data_json.withdraw_status = now.toDate() > openCompare && now.toDate() < closeCompare ? 1 : 0;
        data_json.app_maintainence_msg = settings.app_maintainence_msg;
        data_json.marquee = settings.marquee;
        data_json.maintainence_msg_status = (settings.maintainence_msg_status)?.toString() || '0';

        const versionData = await app_setting_module.findOne();
        if (!versionData) {
            return res.status(404).json({ success: false, msg: 'Version data not found' });
        }

        const formattedDate = moment_timeZone(versionData.app_date).tz('Asia/Kolkata').format('DD MMM YYYY');

        Object.assign(data_json, {
            user_current_version: versionData.user_current_version,
            user_minimum_version: versionData.user_minimum_version,
            pop_status: (versionData.pop_status)?.toString() || '0',
            message: versionData.message,
            link: versionData.link,
            link_btn_text: versionData.link_btn_text,
            action_type: (versionData.action_type).toString() || '',
            action_btn_text: versionData.action_btn_text,
            app_date: formattedDate,
        });

        Object.assign(data_json, {
            wallet_amt: (userData?.wallet_balance)?.toString() || '',
            transfer_point_status: (userData?.transfer_point_status)?.toString() || '',
            betting_status: (userData?.betting_status)?.toString() || '',
            account_block_status: (userData?.status)?.toString() || '',

            main_game_notification_status: (userData?.main_game_notification_status)?.toString() || '1',
            starline_game_notification_status: (userData?.starline_game_notification_status)?.toString() || '1',
            gali_disswar_game_notification_status: (userData?.gali_disswar_game_notification_status)?.toString() || '1',
            other_notification_status: (userData?.other_notification_status)?.toString() || '1',
        });

        const contactData = await contact_settings_module.findOne();
        if (!contactData) {
            return res.status(404).json({ success: false, msg: 'Contact settings not found' });
        }

        data_json.mobile_no = (contactData?.whatsapp_no)?.toString() || '';
        data_json.telegram_no = (contactData?.mobile_1)?.toString() || '';

        const currentDayName = getWeekdayNameInIST(new Date()).toLowerCase();

        // const games = await games_module.aggregate([
        //     { $match: { status: 1 } },
        //     {
        //         $lookup: {
        //             from: 'game_result_histories',
        //             let: { gameId: '$_id' },
        //             pipeline: [
        //                 {
        //                     $match: {
        //                         $expr: {
        //                             $and: [
        //                                 { $eq: ['$gameDB_id', '$$gameId'] },
        //                                 {
        //                                     $gte: [
        //                                         // '$open_decleare_date',
        //                                         '$result_date',
        //                                         moment_timeZone().tz('Asia/Kolkata').startOf('day').toDate()
        //                                     ],
        //                                 },
        //                                 {
        //                                     $lt: [
        //                                         // '$open_decleare_date',
        //                                         '$result_date',
        //                                         moment_timeZone().tz('Asia/Kolkata').endOf('day').toDate()
        //                                     ]
        //                                 }
        //                             ]
        //                         }
        //                     }
        //                 },
        //                 { $sort: { 'open_decleare_date': -1 } }
        //             ],
        //             as: 'todayResults'
        //         }
        //     },
        //     { $unwind: { path: '$todayResults', preserveNullAndEmptyArrays: true } },
        //     {
        //         $group: {
        //             _id: '$_id',
        //             game_name: { $first: '$game_name' },
        //             status: { $first: '$status' },
        //             market_status: { $first: '$market_status' },
        //             open_time: { $first: '$open_time' },
        //             close_time: { $first: '$close_time' },
        //             open_time_sort: { $first: '$open_time_sort' },
        //             result: { $first: '$todayResults' }
        //         }
        //     },
        //     {
        //         $lookup: {
        //             from: 'weekday_games',
        //             let: { gameId: '$_id' },
        //             pipeline: [
        //                 {
        //                     $match: {
        //                         $expr: {
        //                             $and: [
        //                                 { $eq: ['$gameDB_id', '$$gameId'] },
        //                                 { $eq: ['$week_name', currentDayName] }
        //                             ]
        //                         }
        //                     }
        //                 }
        //             ],
        //             as: 'dayTiming'
        //         }
        //     },
        //     { $unwind: { path: '$dayTiming', preserveNullAndEmptyArrays: true } },
        //     {
        //         $addFields: {
        //             open_time: '$dayTiming.open_time',
        //             open_time_sort: '$dayTiming.open_time_sort',
        //             close_time: '$dayTiming.close_time',
        //             market_status: '$dayTiming.weekday_status'
        //         }
        //     },
        //     { $sort: { open_time_sort: 1 } }
        // ]);

        const todayStart = moment_timeZone().tz('Asia/Kolkata').startOf('day').toDate();
        console.log("🚀 ~ apiGetDashboardData ~ todayStart:", todayStart)
        const todayEnd = moment_timeZone().tz('Asia/Kolkata').endOf('day').toDate();
        console.log("🚀 ~ apiGetDashboardData ~ todayEnd:", todayEnd)


        const games = await games_module.aggregate([
            { $match: { status: 1 } },

            // Step 1: Find the latest result where Open was declared TODAY
            {
                $lookup: {
                    from: 'game_result_histories',
                    let: { gameId: '$_id' },
                    pipeline: [
                        {
                            $match: {
                                $expr: {
                                    $and: [
                                        { $eq: ['$gameDB_id', '$$gameId'] },
                                        { $eq: ['$open_decleare_status', 1] },                    // Open must be declared
                                        { $gte: ['$result_date', todayStart] },            // declared today
                                        { $lt: ['$result_date', todayEnd] }
                                    ]
                                }
                            }
                        },
                        { $sort: { open_decleare_date: -1 } },
                        { $limit: 1 }
                    ],
                    as: 'todayOpenResult'
                }
            },

            // Step 2: Unwind (will be empty if no open declared today)
            { $unwind: { path: '$todayOpenResult', preserveNullAndEmptyArrays: true } },

            // Step 3: Re-group the game with the result
            {
                $group: {
                    _id: '$_id',
                    game_name: { $first: '$game_name' },
                    status: { $first: '$status' },
                    market_status: { $first: '$market_status' },
                    open_time: { $first: '$open_time' },
                    close_time: { $first: '$close_time' },
                    open_time_sort: { $first: '$open_time_sort' },
                    resultDoc: { $first: '$todayOpenResult' }  // full document
                }
            },

            // Step 4: Build the final result object exactly the way frontend expects
            {
                $addFields: {
                    result: {
                        $cond: [
                            { $eq: ['$resultDoc', null] },
                            null,  // No open declared today → no result at all

                            // Open is declared → now check if close is also declared
                            {
                                open_number: '$resultDoc.open_number',
                                close_number: {
                                    $cond: [
                                        {
                                            $and: [
                                                { $eq: ['$resultDoc.close_decleare_status', 1] },
                                                { $gte: ['$resultDoc.result_date', todayStart] },
                                                { $lt: ['$resultDoc.result_date', todayEnd] }
                                            ]
                                        },
                                        '$resultDoc.close_number',   // Close declared today → show it
                                        null                         // Close not declared yet → hide it
                                    ]
                                },
                                // Optional: you can also add jodi if you calculate it
                                // jodi: { $concat: ['$resultDoc.open_number', '-', '$resultDoc.close_number'] }
                            }
                        ]
                    }
                }
            },

            // Remove helper field
            { $project: { resultDoc: 0 } },

            // Weekday timing override (unchanged)
            {
                $lookup: {
                    from: 'weekday_games',
                    let: { gameId: '$_id' },
                    pipeline: [
                        {
                            $match: {
                                $expr: {
                                    $and: [
                                        { $eq: ['$gameDB_id', '$$gameId'] },
                                        { $eq: ['$week_name', currentDayName] }
                                    ]
                                }
                            }
                        }
                    ],
                    as: 'dayTiming'
                }
            },
            { $unwind: { path: '$dayTiming', preserveNullAndEmptyArrays: true } },
            {
                $addFields: {
                    open_time: { $ifNull: ['$dayTiming.open_time', '$open_time'] },
                    close_time: { $ifNull: ['$dayTiming.close_time', '$close_time'] },
                    open_time_sort: { $ifNull: ['$dayTiming.open_time_sort', '$open_time_sort'] },
                    market_status: { $ifNull: ['$dayTiming.weekday_status', '$market_status'] }
                }
            },

            { $sort: { open_time_sort: 1 } }
        ]);


        const marketData = games.map(game => {
            const dayTiming = game.dayTiming || {};
            const now = moment_timeZone().tz('Asia/Kolkata');
            const today = now.format('YYYY-MM-DD');

            // FIXED: Proper time formatting
            game.open_time = dayTiming.open_time ? get12HoursTimeFromISO(dayTiming.open_time) : '';
            game.close_time = dayTiming.close_time ? get12HoursTimeFromISO(dayTiming.close_time) : '';
            game.market_status = dayTiming.weekday_status;
            game.open_number = game.result?.open_number || '';
            game.close_number = game.result?.close_number || '';

            if (game.market_status === 0) {
                game.msg = 'Market closed';
                game.msg_status = 2;
            } else {
                // FIXED: Using updated function
                const msgData = getMsgAccordingToTime(dayTiming.open_time, dayTiming.close_time);
                game.msg = msgData.msg;
                game.msg_status = msgData.msg_status;
            }

            if (game.open_number) {
                const str = game.open_number.toString();
                const digits = str.slice(0, 3).split('').map(Number);
                const open_res = (digits[0] + digits[1] + digits[2]) % 10;
                game.open_result = `${str}-${open_res}`;
            } else {
                game.open_result = '';
            }

            if (game.close_number) {
                const str = game.close_number.toString();
                const digits = str.slice(0, 3).split('').map(Number);
                const close_res = (digits[0] + digits[1] + digits[2]) % 10;
                game.close_result = `${close_res}-${str}`;
            } else {
                game.close_result = '';
            }

            // FIXED: Create proper datetime objects for TODAY
            const openTimeToday = moment_timeZone.tz(`${today} ${game.open_time}`, 'YYYY-MM-DD hh:mm A', 'Asia/Kolkata');
            const closeTimeToday = moment_timeZone.tz(`${today} ${game.close_time}`, 'YYYY-MM-DD hh:mm A', 'Asia/Kolkata');

            game.open_duration = openTimeToday.toDate() - now.toDate();
            game.close_duration = closeTimeToday.toDate() - now.toDate();
            game.time_srt = Math.floor(openTimeToday.valueOf() / 1000);

            // Store time in minutes since midnight for sorting (ignores date)
            game.sort_time_minutes = openTimeToday.hours() * 60 + openTimeToday.minutes();

            game.jodi_chart_url = `${process.env.BASE_URL}/game-result-jodi-chart/${game._id}`;
            game.panel_chart_url = `${process.env.BASE_URL}/game-result-panel-chart/${game._id}`;

            delete game.market_status;
            delete game.open_number;
            delete game.close_number;
            delete game.open_decleare_status;
            delete game.close_decleare_status;
            delete game.result;
            delete game.dayTiming;

            return game;
        });

        // FIXED: Sort by time only (minutes since midnight)
        marketData.sort((a, b) => a.sort_time_minutes - b.sort_time_minutes);

        // Remove temporary field
        marketData.forEach(game => {
            delete game.sort_time_minutes;
        });



        const userDeviceLimit = parseInt(process.env.USER_DEVICE_LIMIT);
        if (!userDeviceLimit) {
            return res.status(400).json({ success: false, msg: 'User device limit not set' });
        }

        const device_result = await user_device_record_module.find({ userDB_id: userData._id }).lean().sort({ id: -1 });

        data_json.device_result = device_result.map(v => {
            if (v.logout_status || v.security_pin_status) {
                v.logout_status = v.logout_status.toString();
                v.security_pin_status = v.security_pin_status.toString();
            }
            return v;
        });

        data_json.pana_games_list = await mini_games_module
            .find({}, 'game_name status -_id')
            .lean()
            .then((games) =>
                games.map((game) => ({
                    ...game,
                    status: game.status != null ? String(game.status) : 'N/A',
                }))
            );

        let fixValues = await fix_values_module.findOne({ app_id: 1 });

        data_json.userManualPaymentMode = fixValues?.userManualPaymentMode;
        data_json.userPgPaymentMode = fixValues?.userPgPaymentMode;

        data_json.result = marketData;
        data_json.msg = 'Success';
        data_json.success = true;

        return res.json(data_json);
    } catch (err) {
        console.error('Dashboard error:', err);
        return res.status(500).json({ success: false, msg: 'Internal server error' });
    }
};



const apiGetQRCode = async (req, res) => {
    try {
        const baseUrl = process?.env?.BASE_URL;
        if (!baseUrl) {
            return res.status(500).json({ success: false, msg: "Base URL not set" });
        }

        let { app_key = '', env_type = '' } = req?.body || {};

        // console.log(`(((((((()))))) ~ mobileController.js:2463 ~ apiGetQRCode ~ req.body:`, req.body);

        app_key = toStr(app_key);
        env_type = toStr(env_type);

        if (!app_key || !env_type) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res.json({ success: false, msg: 'UnAuthorized request' });
        }

        let qrcodes = await qrcode_images_module.find().sort({ insert_date: -1 }).limit(1).lean();

        console.log("qrcodes ", qrcodes);

        const qrcode = `${baseUrl}/uploads/qrcode-images/${qrcodes[0]?.qr_image?.toString()}`;

        if (qrcode) {
            return res.json({
                success: true,
                id: qrcodes[0]?._id,
                qrcode,
                msg: 'QRCode Data.',
            });
        } else {
            return res.json({
                success: false,
                qrcode: [],
                msg: 'QRcode not found or not active.',
            });
        }
    } catch (err) {
        console.error('apiGetQRCode error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiUserWalletBalance = async (req, res) => {
    try {
        const userData = req?.user || null;

        if (!userData) {
            return res.status(404).json({
                success: false,
                msg: 'User not found',
            });
        }

        const config = await fix_values_module.findOne().lean();

        if (!config) {
            return res.status(404).json({
                success: false,
                msg: 'Configuration not found',
            });
        }

        const data_json = {
            success: true,
            wallet_balance: userData.wallet_balance?.toString() || 0,
            hold_amt: userData.hold_amount?.toString() || 0,
            transfer_point_status: userData.transfer_point_status?.toString() || 0,
            min_withdrawal: config?.min_withdrawal?.toString() || 0,
            max_withdrawal: config?.max_withdrawal?.toString() || 0,
            min_transfer: config?.min_transfer?.toString() || 0,
            max_transfer: config?.max_transfer?.toString() || 0,
            withdraw_open_time: config?.withdraw_open_time || '',
            withdraw_close_time: config?.withdraw_close_time || '',
            msg: 'User Wallet Balance',
        };
        res.json(data_json);
    } catch (error) {
        console.error('Error in apiUserWalletBalance:', error);
        return res.status(500).json({
            success: false,
            msg: 'Internal Server Error',
        });
    }
};


//  Fixed same date check issue

const apiSubmitBid = async (req, res) => {
    try {
        const {
            new_result = {},
        } = req.body || {};

        let {
            gameDB_id = '',
            Gamename: gameName = '',
            pana = '',
            bid_date = '',
            session_text = '',
            totalbit = '',
            session = '',
            result: bidResult = [],
        } = new_result;

        console.log(`📦 Received bid data:`, new_result);

        // Sanitize inputs
        gameDB_id = toStr(gameDB_id);
        gameName = toStr(gameName);
        pana = toStr(pana);
        bid_date = toStr(bid_date);
        session_text = toStr(session_text);
        totalbit = Number(toStr(totalbit));
        session = toStr(session);
        bidResult = Array.isArray(bidResult) ? bidResult : [];

        const userData = req.user;

        if (!userData) {
            return res.status(404).json({ success: false, msg: 'User not found' });
        }

        // Validate required fields
        if (!gameDB_id || !gameName || !bid_date || !totalbit || bidResult.length === 0) {
            return res.json({
                success: false,
                msg: 'Missing required fields for bid submission.'
            });
        }

        console.log(`📅 Raw bid_date received: "${bid_date}"`);

        // Parse bid_date as IST date (treat string as date in Kolkata TZ)
        let bidMoment = moment_timeZone.tz(bid_date, "YYYY-MMM-DD", "Asia/Kolkata");  // Handles "2025-Dec-01" → Dec 1 IST
        if (!bidMoment.isValid()) {
            console.log(`🔄 Trying fallback parse for: "${bid_date}"`);
            bidMoment = moment_timeZone.tz(bid_date, "DD MMM YYYY", "Asia/Kolkata");  // Fallback format
        }

        if (!bidMoment.isValid()) {
            console.log(`❌ All date parsing failed for: "${bid_date}"`);
            return res.json({
                success: false,
                msg: `Invalid bid date format: "${bid_date}". Please use format like "2025-Dec-01".`
            });
        }

        const bidDate = bidMoment.toDate();  // Now: Dec 1 00:00 IST → Nov 30 18:30 UTC
        console.log("✅ Successfully parsed bidDate:", bidDate);
        console.log("IST Date:", bidMoment.format('DD/MM/YYYY, h:mm:ss a'));

        // Get today's IST start (unchanged)
        const todayIST = moment_timeZone().tz('Asia/Kolkata').startOf('day');
        const today = todayIST.toDate();
        console.log("🚀 ~ apiSubmitBid ~ today:", today);

        // Normalize bid to start of IST day (no need for setHours; use Moment)
        const bidDateNormalizedMoment = bidMoment.startOf('day');
        const bidDateNormalized = bidDateNormalizedMoment.toDate();  // Matches todayIST.toDate()
        console.log("🚀 ~ apiSubmitBid ~ bidDateNormalized:", bidDateNormalized);

        // Compare using Moment (timezone-safe) or timestamps (now aligned)
        const isSameDay = todayIST.isSame(bidDateNormalizedMoment, 'day');  // Or: bidDateNormalized.getTime() === today.getTime()
        console.log("📊 Date Comparison:", {
            today: today.toISOString(),
            bidDate: bidDateNormalized.toISOString(),
            isSameDay
        });

        // Validate date is today
        if (!isSameDay) {
            const todayFormatted = todayIST.format('DD MMM YYYY');
            const bidDateFormatted = bidDateNormalizedMoment.format('DD MMM YYYY');

            return res.json({
                success: false,
                msg: `Sorry, you can only bid for today's date (${todayFormatted}). You tried to bid for ${bidDateFormatted}.`,
            });
        }

        const dayName = getWeekdayNameInIST();
        console.log(`📅 Current day: ${dayName}`);

        // Check game schedule
        const schedule = await weekday_games_module.findOne({
            gameDB_id,
            week_name: dayName.toLowerCase()
        }).lean();
        console.log("🚀 ~ apiSubmitBid ~ schedule:", schedule)

        if (!schedule) {
            return res.json({
                success: false,
                msg: 'No schedule found for this game today.',
                game_status: 2
            });
        }

        if (schedule.weekday_status === 0) {
            return res.json({
                success: false,
                msg: 'Sorry Betting Is Closed',
                game_status: 2
            });
        }

        // Get current time in IST
        const currentIST = moment_timeZone().tz("Asia/Kolkata");
        console.log("🚀 ~ apiSubmitBid ~ currentIST:", currentIST.toString());

        // Extract only time portion from schedule (HH:mm:ss)
        const openTime = moment_timeZone(schedule.open_time).format("HH:mm:ss");
        const closeTime = moment_timeZone(schedule.close_time).format("HH:mm:ss");

        console.log("🚀 ~ apiSubmitBid ~ openTime:", openTime);
        console.log("🚀 ~ apiSubmitBid ~ closeTime:", closeTime);

        // Get current time in HH:mm:ss format for comparison
        const currentTime = currentIST.format("HH:mm:ss");
        console.log("🚀 ~ apiSubmitBid ~ currentTime:", currentTime);

        // Special validation for Jodi Digit, Full Sangam, Half Sangam
        if (['Jodi Digit', 'Full Sangam', 'Half Sangam'].includes(pana)) {
            console.log(`⏰ Special time check for pana type: ${pana}`);
            console.log(`⏰ Current time: ${currentTime}, Open time: ${openTime}`);

            if (currentTime > openTime) {
                return res.json({
                    success: false,
                    msg: `Sorry, betting for ${pana} is closed. It can only be placed before ${openTime}.`,
                    game_status: 2
                });
            }
        }

        // Validate bid amount
        if (totalbit <= 0) {
            return res.json({
                success: false,
                msg: 'Invalid bid amount. Please enter a valid amount.'
            });
        }

        if (userData.wallet_balance < totalbit) {
            return res.json({
                success: false,
                msg: "Sorry, you don't have sufficient amount for this bid.",
                current_balance: userData.wallet_balance,
                required_amount: totalbit
            });
        }

        // Get game rates
        const gameRates = await game_rates_module.findOne({});
        if (!gameRates) {
            return res.json({
                success: false,
                msg: 'Unable to fetch game rates. Please try again.'
            });
        }

        const bidDocs = [];
        const walletHistories = [];
        let calculatedTotal = 0;
        let bidTxIdArray = [];
        let currentUserWallet = userData?.wallet_balance;


        const mainAdmin = await admin_module.findOne({ admin_type: 0 }).lean();
        console.log("🚀 ~ apiSubmitBid ~ mainAdmin:", mainAdmin)

        if (!mainAdmin) {
            return res.status(400).json({
                success: false,
                msg: 'Main admin account not found. Please try again later.'
            });
        }

        // Process each bid entry
        for (const entry of bidResult) {

            const bidTxId = getUserRandomToken(10);
            console.log("🚀 ~ apiSubmitBid ~ bidTxId:", bidTxId)


            const { session: sess, digits, closedigits, points, pana: entryPana } = entry;



            // FIX 1: Use the main pana from request, not entryPana
            const actualPana = pana; // Use the main pana from the request

            console.log(`🎯 Processing bid: pana=${actualPana}, points=${points}, digits=${digits}`);

            // FIX 2: Convert points to number to prevent string concatenation
            const pointsNum = Number(points);
            if (isNaN(pointsNum)) {
                console.log(`❌ Invalid points value: ${points}`);
                return res.json({
                    success: false,
                    msg: 'Invalid points value in bid entry.'
                });
            }

            let winAmt = 0;
            switch (actualPana) {
                case 'Single Digit':
                    winAmt = (gameRates.single_digit_val_2 / gameRates.single_digit_val_1) * pointsNum;
                    break;
                case 'Triple Pana':
                    winAmt = (gameRates.tripple_pana_val_2 / gameRates.tripple_pana_val_1) * pointsNum;
                    break;
                case 'Double Pana':
                    winAmt = (gameRates.double_pana_val_2 / gameRates.double_pana_val_1) * pointsNum;
                    break;
                case 'Single Pana':
                    winAmt = (gameRates.single_pana_val_2 / gameRates.single_pana_val_1) * pointsNum;
                    break;
                case 'Half Sangam':
                    winAmt = (gameRates.half_sangam_val_2 / gameRates.half_sangam_val_1) * pointsNum;
                    break;
                case 'Full Sangam':
                    winAmt = (gameRates.full_sangam_val_2 / gameRates.full_sangam_val_1) * pointsNum;
                    break;
                case 'Jodi Digit':
                    winAmt = (gameRates.jodi_digit_val_2 / gameRates.jodi_digit_val_1) * pointsNum;
                    break;
                case 'Red Bracket':
                    winAmt = (gameRates.red_bracket_val_2 / gameRates.red_bracket_val_1) * pointsNum;
                    break;
                case 'Group Jodi':
                    winAmt = (gameRates.group_jodi_val_2 / gameRates.group_jodi_val_1) * pointsNum;
                    break;
                default:
                    console.log(`⚠️ Unknown pana type: ${actualPana}`);
                    return res.json({
                        success: false,
                        msg: `Unknown pana type: ${actualPana}`
                    });
            }

            calculatedTotal += pointsNum;

            bidDocs.push({
                userDB_id: userData._id,
                gameDB_id,
                game_name: gameName,
                winning_points: winAmt,
                pana: actualPana,
                session: sess,
                digits,
                closedigits,
                points: pointsNum, // Store as number
                bid_date: bidDateNormalized,
                bid_tx_id: bidTxId,
                pay_status: 0
            });

            walletHistories.push({
                userDB_id: userData._id,
                main_gameDB_id: gameDB_id,
                amount: pointsNum, // Store as number
                before_wallet: currentUserWallet,
                transaction_type: 2,
                transaction_note: `Bid Placed For ${gameName} On ${actualPana ? digits : `${digits}-${closedigits}`} (${actualPana})`, //${digits}-${closedigits} 
                amount_status: 5,
                tx_request_number: bidTxId,
                admin_name: mainAdmin?.username,
                admin_type: 0
            });

            bidTxIdArray.push(bidTxId);
            currentUserWallet = currentUserWallet - points; // Deduct points for each entry
            // console.log(`💸 Wallet after deducting points (${points}): ${currentUserWallet}`)
        }

        // FIX 3: Compare numbers properly
        // console.log(`💰 Amount check: frontend total=${totalbit}, calculated=${calculatedTotal}`);
        if (calculatedTotal !== totalbit) {
            // console.log(`⚠️ Amount mismatch: frontend sent ${totalbit} (type: ${typeof totalbit}), calculated ${calculatedTotal} (type: ${typeof calculatedTotal})`);
            return res.json({
                success: false,
                msg: `Bid amount calculation mismatch. Expected: ${totalbit}, Calculated: ${calculatedTotal}. Please try again.`
            });
        }


        // console.log("walletHistories walletHistories  ", walletHistories);


        // Save all bids and transactions
        await bid_history_module.insertMany(bidDocs);
        await wallet_trans_history_module.insertMany(walletHistories);

        // Update user wallet
        userData.wallet_balance -= totalbit;
        await userData.save();

        // add bid amount to the main admin wallet account
        await admin_module.findOneAndUpdate({ admin_type: 0 }, { $inc: { wallet_amount: totalbit } }, { new: true });

        console.log(`✅ Bid submitted successfully for user: ${userData._id}, amount: ${totalbit}`);

        return res.json({
            success: true,
            msg: 'Bid Successfully Submitted',
            transaction_ids: bidTxIdArray,
            new_balance: userData.wallet_balance
        });

    } catch (err) {
        console.error('❌ apiSubmitBid error:', err);
        return res.status(500).json({
            success: false,
            msg: 'Internal Server Error'
        });
    }
};


// const apiSubmitBid = async (req, res) => {
//     try {
//         const {
//             new_result = {},
//         } = req.body || {};

//         let {
//             gameDB_id = '',
//             Gamename: gameName = '',
//             pana = '',
//             bid_date = '',
//             session_text = '',
//             totalbit = '',
//             session = '',
//             result: bidResult = [],
//         } = new_result;

//         console.log(`📦 Received bid data:`, new_result);

//         // Sanitize inputs
//         gameDB_id = toStr(gameDB_id);
//         gameName = toStr(gameName);
//         pana = toStr(pana);
//         bid_date = toStr(bid_date);
//         session_text = toStr(session_text);
//         totalbit = Number(toStr(totalbit));
//         session = toStr(session);
//         bidResult = Array.isArray(bidResult) ? bidResult : [];

//         const userData = req.user;

//         if (!userData) {
//             return res.status(404).json({ success: false, msg: 'User not found' });
//         }

//         // Validate required fields
//         if (!gameDB_id || !gameName || !bid_date || !totalbit || bidResult.length === 0) {
//             return res.json({
//                 success: false,
//                 msg: 'Missing required fields for bid submission.'
//             });
//         }

//         console.log(`📅 Raw bid_date received: "${bid_date}"`);

//         // Parse and validate bidding date using the updated parseCustomDate
//         let bidDate = parseCustomDate(bid_date);

//         // If parseCustomDate returns null, try moment.js as fallback
//         if (!bidDate || isNaN(bidDate.getTime())) {
//             console.log(`🔄 Trying moment.js fallback for: "${bid_date}"`);
//             try {
//                 bidDate = moment_timeZone.tz(bid_date, "DD MMM YYYY", "Asia/Kolkata").toDate();
//             } catch (momentError) {
//                 console.log('❌ Moment.js parsing failed:', momentError);
//             }
//         }

//         // Final validation
//         if (!bidDate || isNaN(bidDate.getTime())) {
//             console.log(`❌ All date parsing failed for: "${bid_date}"`);
//             return res.json({
//                 success: false,
//                 msg: `Invalid bid date format: "${bid_date}". Please use format like "30 Sept 2025".`
//             });
//         }

//         console.log("✅ Successfully parsed bidDate:", bidDate);
//         console.log("IST Date:", bidDate.toLocaleString("en-IN", { timeZone: "Asia/Kolkata" }));

//         // Get today's date in IST
//         const todayIST = moment_timeZone().tz('Asia/Kolkata').startOf('day');
//         console.log("🚀 ~ apiSubmitBid ~ todayIST:", todayIST)
//         const today = todayIST.toDate();
//         console.log("🚀 ~ apiSubmitBid ~ today:", today)

//         // Normalize bid date to start of day for comparison
//         const bidDateNormalized = new Date(bidDate);
//         console.log("🚀 ~ apiSubmitBid ~ bidDateNormalized:", bidDateNormalized)
//         bidDateNormalized.setHours(0, 0, 0, 0);

//         console.log("📊 Date Comparison:", {
//             today: today.toISOString(),
//             bidDate: bidDateNormalized.toISOString(),
//             isSameDay: bidDateNormalized.getTime() === today.getTime()
//         });

//         // Validate date is today
//         if (bidDateNormalized.getTime() !== today.getTime()) {
//             const todayFormatted = todayIST.format('DD MMM YYYY');
//             const bidDateFormatted = moment_timeZone(bidDateNormalized).format('DD MMM YYYY');

//             return res.json({
//                 success: false,
//                 msg: `Sorry, you can only bid for today's date (${todayFormatted}). You tried to bid for ${bidDateFormatted}.`,
//             });
//         }

//         const dayName = getWeekdayNameInIST();
//         console.log(`📅 Current day: ${dayName}`);

//         // Check game schedule
//         const schedule = await weekday_games_module.findOne({
//             gameDB_id,
//             week_name: dayName.toLowerCase()
//         }).lean();
//         console.log("🚀 ~ apiSubmitBid ~ schedule:", schedule)

//         if (!schedule) {
//             return res.json({
//                 success: false,
//                 msg: 'No schedule found for this game today.',
//                 game_status: 2
//             });
//         }

//         if (schedule.weekday_status === 0) {
//             return res.json({
//                 success: false,
//                 msg: 'Sorry Betting Is Closed',
//                 game_status: 2
//             });
//         }

//         // Get current time in IST
//         const currentIST = moment_timeZone().tz("Asia/Kolkata");
//         console.log("🚀 ~ apiSubmitBid ~ currentIST:", currentIST.toString());

//         // Extract only time portion from schedule (HH:mm:ss)
//         const openTime = moment_timeZone(schedule.open_time).format("HH:mm:ss");
//         const closeTime = moment_timeZone(schedule.close_time).format("HH:mm:ss");

//         console.log("🚀 ~ apiSubmitBid ~ openTime:", openTime);
//         console.log("🚀 ~ apiSubmitBid ~ closeTime:", closeTime);

//         // Get current time in HH:mm:ss format for comparison
//         const currentTime = currentIST.format("HH:mm:ss");
//         console.log("🚀 ~ apiSubmitBid ~ currentTime:", currentTime);

//         // Special validation for Jodi Digit, Full Sangam, Half Sangam
//         if (['Jodi Digit', 'Full Sangam', 'Half Sangam'].includes(pana)) {
//             console.log(`⏰ Special time check for pana type: ${pana}`);
//             console.log(`⏰ Current time: ${currentTime}, Open time: ${openTime}`);

//             if (currentTime > openTime) {
//                 return res.json({
//                     success: false,
//                     msg: `Sorry, betting for ${pana} is closed. It can only be placed before ${openTime}.`,
//                     game_status: 2
//                 });
//             }
//         }





//         // Validate bid amount
//         if (totalbit <= 0) {
//             return res.json({
//                 success: false,
//                 msg: 'Invalid bid amount. Please enter a valid amount.'
//             });
//         }

//         if (userData.wallet_balance < totalbit) {
//             return res.json({
//                 success: false,
//                 msg: "Sorry, you don't have sufficient amount for this bid.",
//                 current_balance: userData.wallet_balance,
//                 required_amount: totalbit
//             });
//         }

//         // Get game rates
//         const gameRates = await game_rates_module.findOne({});
//         if (!gameRates) {
//             return res.json({
//                 success: false,
//                 msg: 'Unable to fetch game rates. Please try again.'
//             });
//         }

//         const bidDocs = [];
//         const walletHistories = [];
//         let calculatedTotal = 0;
//         let bidTxIdArray = [];
//         let currentUserWallet = userData?.wallet_balance;


//         const mainAdmin = await admin_module.findOne({ admin_type: 0 }).lean();
//         console.log("🚀 ~ apiSubmitBid ~ mainAdmin:", mainAdmin)

//         if (!mainAdmin) {
//             return res.status(400).json({
//                 success: false,
//                 msg: 'Main admin account not found. Please try again later.'
//             });
//         }

//         // Process each bid entry
//         for (const entry of bidResult) {

//             const bidTxId = getUserRandomToken(10);
//             console.log("🚀 ~ apiSubmitBid ~ bidTxId:", bidTxId)


//             const { session: sess, digits, closedigits, points, pana: entryPana } = entry;



//             // FIX 1: Use the main pana from request, not entryPana
//             const actualPana = pana; // Use the main pana from the request

//             console.log(`🎯 Processing bid: pana=${actualPana}, points=${points}, digits=${digits}`);

//             // FIX 2: Convert points to number to prevent string concatenation
//             const pointsNum = Number(points);
//             if (isNaN(pointsNum)) {
//                 console.log(`❌ Invalid points value: ${points}`);
//                 return res.json({
//                     success: false,
//                     msg: 'Invalid points value in bid entry.'
//                 });
//             }

//             let winAmt = 0;
//             switch (actualPana) {
//                 case 'Single Digit':
//                     winAmt = (gameRates.single_digit_val_2 / gameRates.single_digit_val_1) * pointsNum;
//                     break;
//                 case 'Triple Pana':
//                     winAmt = (gameRates.tripple_pana_val_2 / gameRates.tripple_pana_val_1) * pointsNum;
//                     break;
//                 case 'Double Pana':
//                     winAmt = (gameRates.double_pana_val_2 / gameRates.double_pana_val_1) * pointsNum;
//                     break;
//                 case 'Single Pana':
//                     winAmt = (gameRates.single_pana_val_2 / gameRates.single_pana_val_1) * pointsNum;
//                     break;
//                 case 'Half Sangam':
//                     winAmt = (gameRates.half_sangam_val_2 / gameRates.half_sangam_val_1) * pointsNum;
//                     break;
//                 case 'Full Sangam':
//                     winAmt = (gameRates.full_sangam_val_2 / gameRates.full_sangam_val_1) * pointsNum;
//                     break;
//                 case 'Jodi Digit':
//                     winAmt = (gameRates.jodi_digit_val_2 / gameRates.jodi_digit_val_1) * pointsNum;
//                     break;
//                 case 'Red Bracket':
//                     winAmt = (gameRates.red_bracket_val_2 / gameRates.red_bracket_val_1) * pointsNum;
//                     break;
//                 case 'Group Jodi':
//                     winAmt = (gameRates.group_jodi_val_2 / gameRates.group_jodi_val_1) * pointsNum;
//                     break;
//                 default:
//                     console.log(`⚠️ Unknown pana type: ${actualPana}`);
//                     return res.json({
//                         success: false,
//                         msg: `Unknown pana type: ${actualPana}`
//                     });
//             }

//             calculatedTotal += pointsNum;

//             bidDocs.push({
//                 userDB_id: userData._id,
//                 gameDB_id,
//                 game_name: gameName,
//                 winning_points: winAmt,
//                 pana: actualPana,
//                 session: sess,
//                 digits,
//                 closedigits,
//                 points: pointsNum, // Store as number
//                 bid_date: bidDateNormalized,
//                 bid_tx_id: bidTxId,
//                 pay_status: 0
//             });

//             walletHistories.push({
//                 userDB_id: userData._id,
//                 main_gameDB_id: gameDB_id,
//                 amount: pointsNum, // Store as number
//                 before_wallet: currentUserWallet,
//                 transaction_type: 2,
//                 transaction_note: `Bid Placed For ${gameName} On ${actualPana ? digits : `${digits}-${closedigits}`} (${actualPana})`, //${digits}-${closedigits} 
//                 amount_status: 5,
//                 tx_request_number: bidTxId,
//                 admin_name: mainAdmin?.username,
//                 admin_type: 0
//             });

//             bidTxIdArray.push(bidTxId);
//             currentUserWallet = currentUserWallet - points; // Deduct points for each entry
//             // console.log(`💸 Wallet after deducting points (${points}): ${currentUserWallet}`)
//         }

//         // FIX 3: Compare numbers properly
//         // console.log(`💰 Amount check: frontend total=${totalbit}, calculated=${calculatedTotal}`);
//         if (calculatedTotal !== totalbit) {
//             // console.log(`⚠️ Amount mismatch: frontend sent ${totalbit} (type: ${typeof totalbit}), calculated ${calculatedTotal} (type: ${typeof calculatedTotal})`);
//             return res.json({
//                 success: false,
//                 msg: `Bid amount calculation mismatch. Expected: ${totalbit}, Calculated: ${calculatedTotal}. Please try again.`
//             });
//         }


//         // console.log("walletHistories walletHistories  ", walletHistories);


//         // Save all bids and transactions
//         await bid_history_module.insertMany(bidDocs);
//         await wallet_trans_history_module.insertMany(walletHistories);

//         // Update user wallet
//         userData.wallet_balance -= totalbit;
//         await userData.save();

//         // add bid amount to the main admin wallet account
//         await admin_module.findOneAndUpdate({ admin_type: 0 }, { $inc: { wallet_amount: totalbit } }, { new: true });

//         console.log(`✅ Bid submitted successfully for user: ${userData._id}, amount: ${totalbit}`);

//         return res.json({
//             success: true,
//             msg: 'Bid Successfully Submitted',
//             transaction_ids: bidTxIdArray,
//             new_balance: userData.wallet_balance
//         });

//     } catch (err) {
//         console.error('❌ apiSubmitBid error:', err);
//         return res.status(500).json({
//             success: false,
//             msg: 'Internal Server Error'
//         });
//     }
// };


const apiUpdateUserNotificationControl = async (req, res) => {
    try {
        console.log("🚀 ~ file: mobileController.js:3146 ~ apiUpdateUserNotificationControl ~ req.body:", req?.body);

        const {
            main_game_notification_status,
            gali_disswar_game_notification_status,
            starline_game_notification_status,
            other_notification_status
        } = req?.body;

        const userData = req?.user || null;

        if (!userData || !userData._id) {
            return res.status(401).json({ success: false, msg: 'User not found' });
        }

        // Check if at least one notification status is provided
        if (
            main_game_notification_status === undefined &&
            gali_disswar_game_notification_status === undefined &&
            starline_game_notification_status === undefined &&
            other_notification_status === undefined
        ) {
            return res.status(400).json({
                success: false,
                msg: 'At least one notification status is required'
            });
        }

        // Prepare update object with only provided fields
        const updateFields = {};

        if (main_game_notification_status !== undefined) {
            updateFields.main_game_notification_status = main_game_notification_status;
        }
        if (gali_disswar_game_notification_status !== undefined) {
            updateFields.gali_disswar_game_notification_status = gali_disswar_game_notification_status;
        }
        if (starline_game_notification_status !== undefined) {
            updateFields.starline_game_notification_status = starline_game_notification_status;
        }
        if (other_notification_status !== undefined) {
            updateFields.other_notification_status = other_notification_status;
        }

        // Add last update timestamp
        updateFields.last_update = new Date();

        // Update user notification settings in database
        const updatedUser = await user_module.findByIdAndUpdate(
            userData._id,
            { $set: updateFields },
            { new: true, select: 'main_game_notification_status gali_disswar_game_notification_status starline_game_notification_status other_notification_status' }
        );

        if (!updatedUser) {
            return res.status(404).json({
                success: false,
                msg: 'User not found in database'
            });
        }

        return res.json({
            success: true,
            msg: 'User notification status updated successfully',
            data: {
                main_game_notification_status: updatedUser.main_game_notification_status,
                gali_disswar_game_notification_status: updatedUser.gali_disswar_game_notification_status,
                starline_game_notification_status: updatedUser.starline_game_notification_status,
                other_notification_status: updatedUser.other_notification_status
            }
        });

    } catch (error) {
        console.log("🚀 ~ apiUpdateUserNotificationControl ~ error:", error);
        return res.status(500).json({
            success: false,
            msg: 'Internal server error',
            error: error.message
        });
    }
};


const apiGetNotification = async (req, res) => {
    try {
        const userData = req?.user || null;
        if (!userData) {
            return res.status(404).json({ success: false, msg: 'User not found' });
        }

        const notifs = await user_notification_module.find({ userDB_id: userData._id })
            .sort({ _id: -1 })

        if (notifs.length > 0) {
            // Format insert_date: 'DD MMM YYYY h:mm:ss A'
            const formatted = notifs.map(n => ({
                title: n.title || '',
                msg: n.msg,
                insert_date: new Date(n.insert_date).toLocaleString('en-US', {
                    day: '2-digit', month: 'short', year: 'numeric',
                    hour: 'numeric', minute: 'numeric', second: 'numeric', hour12: true
                })
            }));

            return res.json({ success: true, notification: formatted, msg: 'Notification Data Available' });
        } else {
            return res.json({ success: false, notification: [], msg: 'Notification Data Not Available' });
        }
    } catch (err) {
        console.error('apiGetNotification error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};



const apiGetBellNotification = async (req, res) => {
    try {
        const userData = req?.user || null;
        console.log("🚀 ~ apiGetBellNotification ~ userData:", userData);

        if (!userData || !userData._id || !userData.insert_date) {
            return res.status(401).json({ success: false, msg: 'User not found' });
        }

        // === STEP 1: Update user's last seen time (this removes red dot) ===
        await user_module.updateOne(
            { _id: userData._id },
            { $set: { last_seen_notification_at: new Date() } }
        );

        // Convert user's insert_date to Date object
        const userInsertDate = new Date(userData.insert_date);
        console.log("🚀 ~ apiGetBellNotification ~ userInsertDate:", userInsertDate)

        // Fetch notifications inserted AFTER the user's register date
        // const welcomeNotification = await user_notification_module.find({
        //     userDB_id: userData._id,
        // });



        const userNotification = await user_notification_module.find({
            // userDB_id: null,
            insert_date: { $gte: userInsertDate }
        });
        const filteredNotificatioins = userNotification.filter(n => {
            if (n.userDB_id) {
                if (n.userDB_id.toString() == userData._id.toString()) {
                    return n;
                }
            }
            else return n;
        })
        // console.log("🚀 ~ apiGetBellNotification ~ userNotification:", userNotification)
        // console.log("🚀 ~ apiGetBellNotification ~ filteredNotificatioins:", filteredNotificatioins)
        // Sort latest first
        const notification = [...filteredNotificatioins].sort(//...welcomeNotification, ...userNotification
            (a, b) => new Date(b.insert_date) - new Date(a.insert_date)
        );

        const formattedNotices = notification.map(n => ({
            ...n._doc,
            insert_date: formatDateToDDMMYYYY(n.insert_date)
        }));

        return res.json({
            success: formattedNotices.length > 0,
            notices: formattedNotices,
            msg: formattedNotices.length > 0 ? 'Notice Data.' : 'Data Not Found.',
        });

    } catch (err) {
        console.error('Error in apiGetBellNotification:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};


// const apiGetBellNotification = async (req, res) => {
//     try {
//         const userData = req?.user || null;

//         if (!userData || !userData._id) {
//             return res.status(401).json({ success: false, msg: 'User not found' });
//         }

//         // === STEP 1: Update user's last seen time (this removes red dot) ===
//         await user_module.updateOne(
//             { _id: userData._id },
//             { $set: { last_seen_notification_at: new Date() } }
//         );

//         // === STEP 2: Fetch notifications newer than last seen ===
//         const lastSeen = userData.last_seen_notification_at
//             ? new Date(userData.last_seen_notification_at)
//             : new Date(0); // first time user

//         const notifications = await user_notification_module.find({
//             insert_date: { $gt: lastSeen } // only NEWER than last seen
//         }).sort({ insert_date: -1 });

//         // Filter: broadcast (userDB_id null) OR personal (to this user)
//         const filtered = notifications.filter(n =>
//             !n.userDB_id || n.userDB_id.toString() === userData._id.toString()
//         );

//         const formattedNotices = filtered.map(n => ({
//             ...n._doc,
//             insert_date: formatDateToDDMMYYYY(n.insert_date)
//         }));

//         return res.json({
//             success: true,
//             notices: formattedNotices,
//             has_unread: formattedNotices.length > 0,  // ← For future use
//             msg: formattedNotices.length > 0 ? 'Notice Data.' : 'No new notifications.',
//         });

//     } catch (err) {
//         console.error('Error in apiGetBellNotification:', err);
//         return res.status(500).json({ success: false, msg: 'Internal Server Error' });
//     }
// };



// GET /api/check-notification-dot
const apiCheckNotificationDot = async (req, res) => {
    try {
        const userData = req?.user;
        if (!userData) return res.json({ has_unread: false });

        const lastSeen = userData.last_seen_notification_at
            ? new Date(userData.last_seen_notification_at)
            : new Date(0);

        const hasNew = await user_notification_module.exists({
            insert_date: { $gt: lastSeen },
            $or: [
                { userDB_id: null },                    // broadcast
                { userDB_id: userData._id }             // personal
            ]
        });

        res.json({ has_unread: !!hasNew });
    } catch (err) {
        res.json({ has_unread: false });
    }
};




const apiSubmitIdea = async (req, res) => {
    try {
        let { idea } = req.body;

        // Validate idea
        idea = toStr(idea).trim();
        if (!idea || idea.length < 3) {
            return res.status(400).json({
                success: false,
                msg: "Idea is required and must be at least 3 characters long.",
            });
        }

        const userData = req.user;

        if (!userData || !userData._id) {
            return res.status(401).json({
                success: false,
                msg: "Unauthorized access. User data not found.",
            });
        }

        const submission = new ideas_module({
            userDB_id: userData._id,
            ideas: idea,
        });

        await submission.save();

        return res.json({
            success: true,
            msg: "Idea submitted successfully.",
        });

    } catch (err) {
        console.error("apiSubmitIdea error:", err);
        return res.status(500).json({
            success: false,
            msg: "Internal Server Error. Please try again later.",
        });
    }
};

const apiBidHistoryData = async (req, res) => {
    try {
        let {
            // bid_from = '',
            // bid_to = '', 
            session = 'Both',
            gameListId,
            page,
            limit
        } = req?.body || {};

        console.log("🚀 ------------------------- ~ apiBidHistoryData ~ req?.body:", req?.body)


        page = Number(page) || 1;
        limit = Number(limit) || 10;
        const skip = (page - 1) * limit;

        const parseCustomDate = (dateStr) => {
            if (!dateStr || typeof dateStr !== 'string') return null;

            const [day, monStr, year] = dateStr.split('-');
            const monthMap = {
                Jan: 0, Feb: 1, Mar: 2, Apr: 3, May: 4, Jun: 5,
                Jul: 6, Aug: 7, Sep: 8, Oct: 9, Nov: 10, Dec: 11
            };
            const month = monthMap[monStr];
            if (!day || month === undefined || !year) return null;

            return new Date(Number(year), month, Number(day), 0, 0, 0, 0);
        };

        // bid_from = parseCustomDate(toStr(bid_from));
        // bid_to = parseCustomDate(toStr(bid_to));  // removed date filter for show all history in application

        const userData = req?.user || null;
        if (!userData) {
            return res.status(404).json({ success: false, msg: 'User not found' });
        }

        const filter = {
            userDB_id: userData._id,
        };

        if (session == 'Open') {
            filter.session = session
        }

        if (session == 'Close') {
            filter.session = session
        }

        if (gameListId.length > 0) {
            filter.gameDB_id = { $in: gameListId };
        }

        // Date filter setup
        // if (!bid_from && !bid_to) {
        //     const todayIST = moment_timeZone().tz('Asia/Kolkata').startOf('day');
        //     const todayUTC = new Date(todayIST.toDate().getTime() - (5.5 * 60 * 60 * 1000));
        //     const tomorrowUTC = new Date(todayUTC.getTime() + 24 * 60 * 60 * 1000);
        //     filter.insert_date = { $gte: todayUTC, $lt: tomorrowUTC };
        // } else {
        //     const toUTCFromIST = (date, hour, min, sec, ms = 0) => {
        //         if (!(date instanceof Date)) return null;
        //         const istDate = new Date(date);
        //         istDate.setHours(hour, min, sec, ms);
        //         return new Date(istDate.getTime() - (5.5 * 60 * 60 * 1000));
        //     };

        //     const dateFilter = {};
        //     if (bid_from) dateFilter.$gte = toUTCFromIST(bid_from, 0, 0, 0, 0);
        //     if (bid_to) dateFilter.$lte = toUTCFromIST(bid_to, 23, 59, 59, 999);
        //     filter.insert_date = dateFilter;
        // }

        // const [bids1, bids2, bids3] = await Promise.all([
        //     bid_history_module.find(filter).lean(),
        //     starline_bid_history_module.find(filter).lean(),
        //     gali_disswar_bid_history_module.find(filter).lean()
        // ]);

        // console.log("🚀 ~ apiBidHistoryData ~ filter:", filter)

        const totalBidCount = await bid_history_module.countDocuments(filter);
        console.log("🚀 ~ apiBidHistoryData ~ totalBidCount:", totalBidCount);


        const bids1 = await bid_history_module
            .find(filter)  // Start the query
            .sort({ insert_date: -1 })  // Sort descending by insert_date (server-side)
            .skip(skip)    // Pagination: skip records
            .limit(limit)  // Pagination: limit records
            .lean();       // Return plain objects (faster, no Mongoose docs)
        // console.log("🚀 ~ apiBidHistoryData ~ bids1:", bids1)

        // const allBids = [...bids1, ...bids2, ...bids3];
        const allBids = [...bids1];
        console.log("🚀 ~ apiBidHistoryData ~ allBids:", allBids)

        if (allBids.length > 0) {
            const formatted = allBids.map(b => ({
                ...b,
                points: String(b.points),
                closedigits: b.closedigits || '',
                pay_status: String(b.pay_status),
                winning_points: String(b.winning_points),
                status: b.status !== undefined ? String(b.status) : '0',
                bid_date: moment_timeZone.tz(b.insert_date, 'Asia/Kolkata').format('DD MMM YYYY hh:mm:ss A')
            }));

            // Sort by pay_status ASC, then _id DESC
            // formatted.sort((a, b) => {
            //     const statusDiff = Number(a.pay_status) - Number(b.pay_status);
            //     if (statusDiff !== 0) return statusDiff;
            //     return String(b._id).localeCompare(String(a._id));
            // });

            return res.json({ success: true, bid_data: formatted, msg: 'Bid History Data Available', total_count: totalBidCount });
        }

        return res.json({ success: false, bid_data: [], msg: 'Bid History Data Not Available' });

    } catch (err) {
        console.error('apiBidHistoryData error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiJackpotBidHistoryData = async (req, res) => {
    try {
        let { bid_from = '', bid_to = '' } = req?.body || {};

        const parseCustomDate = (dateStr) => {
            if (!dateStr || typeof dateStr !== 'string') return null;

            const [day, monStr, year] = dateStr.split('-');
            const monthMap = {
                Jan: 0, Feb: 1, Mar: 2, Apr: 3, May: 4, Jun: 5,
                Jul: 6, Aug: 7, Sep: 8, Oct: 9, Nov: 10, Dec: 11
            };
            const month = monthMap[monStr];
            if (!day || month === undefined || !year) return null;

            return new Date(Number(year), month, Number(day), 0, 0, 0, 0);
        };

        bid_from = parseCustomDate(toStr(bid_from));
        bid_to = parseCustomDate(toStr(bid_to));

        const userData = req?.user || null;
        if (!userData) {
            return res.status(404).json({ success: false, msg: 'User not found' });
        }

        const filter = { userDB_id: userData._id };

        // Date filter setup
        if (!bid_from && !bid_to) {
            const todayIST = moment_timeZone().tz('Asia/Kolkata').startOf('day');
            const todayUTC = new Date(todayIST.toDate().getTime() - (5.5 * 60 * 60 * 1000));
            const tomorrowUTC = new Date(todayUTC.getTime() + 24 * 60 * 60 * 1000);
            filter.insert_date = { $gte: todayUTC, $lt: tomorrowUTC };
        }
        else {
            const toUTCFromIST = (dateStr, hour, min, sec, ms = 0) => {
                if (!dateStr) return null;

                // Parse "DD-MMM-YYYY" in Asia/Kolkata timezone
                const istMoment = moment_timeZone.tz(dateStr, "DD-MMM-YYYY", "Asia/Kolkata");

                // Set custom time in IST
                istMoment.set({ hour, minute: min, second: sec, millisecond: ms });

                // Convert to UTC Date object
                return istMoment.clone().tz("UTC").toDate();
            };

            const dateFilter = {};
            if (bid_from) dateFilter.$gte = toUTCFromIST(bid_from, 0, 0, 0, 0);
            if (bid_to) dateFilter.$lte = toUTCFromIST(bid_to, 23, 59, 59, 999);

            filter.insert_date = dateFilter;
        }

        const bids1 = await gali_disswar_bid_history_module.find(filter).lean()

        if (bids1) {
            const formattedData = bids1.map(bid => ({
                ...bid,
                insert_date: moment_timeZone(bid.insert_date).tz("Asia/Kolkata").format("DD-MMM-YYYY"),
                bid_date: moment_timeZone(bid.bid_date).tz("Asia/Kolkata").format("DD-MMM-YYYY"),
            }));
            return res.json({ success: true, bid_data: formattedData, msg: 'Bid History Data Available' });
        }

        return res.json({ success: false, bid_data: [], msg: 'Bid History Data Not Available' });

    } catch (err) {
        console.error('apiBidHistoryData error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiUserWithdrawFundRequest = async (req, res) => {
    try {
        let { request_amount = "" } = req?.body || {};
        const userData = req?.user || null;

        request_amount = Number(toStr(request_amount));

        if (!userData || !userData._id) {
            return res.status(401).json({ success: false, msg: 'User not found' });
        }

        if (!request_amount || request_amount <= 0) {
            return res.status(400).json({ success: false, msg: 'Invalid withdrawal amount' });
        }

        const withdrawSettings = await fix_values_module.findOne();

        console.log("🚀 ~ apiUserWithdrawFundRequest ~ withdrawSettings:", withdrawSettings)

        if (!withdrawSettings || !withdrawSettings.withdraw_open_time || !withdrawSettings.withdraw_close_time) {
            return res.status(200).json({ success: false, msg: 'Withdrawal settings are incomplete' });
        }

        // DB Times (IST)
        const openTimeIST = withdrawSettings?.withdraw_open_time;   // "08:30"
        const closeTimeIST = withdrawSettings?.withdraw_close_time;  // "18:00"

        // Get current IST time
        const now = new Date().toLocaleString("en-US", { timeZone: "Asia/Kolkata" });
        const nowDate = new Date(now);

        // Convert current time to total minutes
        const currentMinutes = nowDate.getHours() * 60 + nowDate.getMinutes();

        // Convert open & close time to total minutes
        const [openHour, openMin] = openTimeIST.split(":").map(Number);
        const [closeHour, closeMin] = closeTimeIST.split(":").map(Number);

        const openMinutes = openHour * 60 + openMin;
        const closeMinutes = closeHour * 60 + closeMin;

        // ✅ Final check
        if (currentMinutes < openMinutes || currentMinutes > closeMinutes) {
            return res.json({
                success: false,
                msg: `Sorry, you can withdraw only between ${openTimeIST} to ${closeTimeIST} IST`
            });
        }



        const user_before_wallet_balance = userData.wallet_balance || 0;

        if (userData.wallet_balance < request_amount) {
            return res.json({
                success: false,
                msg: `Sorry ${userData.user_name}, you don't have sufficient balance to withdraw`,
            });
        }

        const bankDetails = await user_bank_details_module.findOne({ userDB_id: userData._id }).lean()
        if (!bankDetails) {
            return res.json({
                success: false,
                msg: 'User bank or UPI details not found',
            });
        }

        const tx_request_number = 'WD_TR_' + getUserRandomToken(15);


        
        const autoWithdrawViaPG = Number(withdrawSettings?.autoWithdrawPgType);



        const withdrawData = {
            userDB_id: userData._id,
            amount: request_amount,
            tx_request_number,
            bank_name: bankDetails?.bank_name,
            branch_address: bankDetails?.branch_address,
            ac_holder_name: bankDetails?.ac_holder_name,
            ac_number: bankDetails?.ac_number,
            ifsc_code: bankDetails?.ifsc_code,
            payment_method : autoWithdrawViaPG
        };

        const newRequest = await withdraw_fund_request_module.create(withdrawData);

        console.log("🚀 ~ apiUserWithdrawFundRequest ~ newRequest:", newRequest)

        if (!newRequest || !newRequest._id) {
            return res.json({
                success: false,
                msg: 'Failed to create withdraw request. Please try again later.',
            });
        }

        // console.log("AUTO STATUS:", withdrawSettings.autoWithdrawalStatus, typeof withdrawSettings.autoWithdrawalStatus);
        // console.log("MIN:", withdrawSettings.autoWithdrawalMinAmount, typeof withdrawSettings.autoWithdrawalMinAmount);
        // console.log("MAX:", withdrawSettings.autoWithdrawalMaxAmount, typeof withdrawSettings.autoWithdrawalMaxAmount);
        // console.log("REQUEST:", request_amount, typeof request_amount);

        // if (withdrawSettings?.autoWithdrawalStatus == 1 && request_amount >= withdrawSettings?.autoWithdrawalMinAmount && request_amount <= withdrawSettings.autoWithdrawalMaxAmount) {


        const autoStatus = Number(withdrawSettings?.autoWithdrawalStatus);
        const autoMin = Number(withdrawSettings?.autoWithdrawalMinAmount);
        const autoMax = Number(withdrawSettings?.autoWithdrawalMaxAmount);
        const reqAmt = Number(request_amount);


        // const autoStatus = Number(withdrawSettings?.autoWithdrawalStatus);
        // const autoMin = Number(withdrawSettings?.autoWithdrawalMinAmount);
        // const autoMax = Number(withdrawSettings?.autoWithdrawalMaxAmount);
        // const reqAmt = Number(request_amount);

        console.log("✅ FIXED AUTO CHECK:", {
            autoStatus,
            autoMin,
            autoMax,
            reqAmt,
            types: {
                autoStatus: typeof autoStatus,
                autoMin: typeof autoMin,
                autoMax: typeof autoMax,
                reqAmt: typeof reqAmt,
                reqAmt: typeof autoWithdrawViaPG,
            }
        });

        const user = await user_module.findById(userData._id);
        // if (autoStatus === 1 && reqAmt >= autoMin && reqAmt <= autoMax) {

        //     console.log("🚀 autoWithdrawViaPG == 7 ::::::::", autoWithdrawViaPG == 7)
        //     if (autoWithdrawViaPG == 7) { 
        // 

        if (autoStatus === 1 && reqAmt >= autoMin && reqAmt <= autoMax) {

            console.log("🚀 autoWithdrawViaPG == 7 ::::::::", autoWithdrawViaPG == 7);

            // if (autoWithdrawViaPG === 7) { // 7=dollar bazar payout

            //     console.log("🚀 AUTO WITH DOLLAR BAZAR---------------------------------- inside done ")

            //     const withdraw_reqDB_id = newRequest?._id;
            //     const remark = "Auto approve withdrawal request";
            //     const payment_method = 7;  // 7 = auto withdrawal approve via dollar bazar payout payment gateway

            //     const payout = await doPayout(
            //         request_amount,
            //         bankDetails,
            //         tx_request_number
            //     );
            //     console.log("🚀 ~ approveWithdrawRequest ```````admin controller````` ~ payout:", payout)

            //     const record = await withdraw_fund_request_module.findById(withdraw_reqDB_id);

            //     if (payout.status === "FAILED") {

            //         record.fund_status = 2;
            //         record.remark = payout.message;
            //         await record.save();

            //         return res.json({
            //             success: false,
            //             msg: `Payout Failed: ${payout.message}`,
            //         });
            //     }

            //     // SUCCESS
            //     user.wallet_balance -= request_amount;
            //     await user.save();

            //     const adminData = await admin_module.findOneAndUpdate({ admin_type: 0 }, { $inc: { wallet_amount: request_amount } })

            //     await wallet_trans_history_module.create({
            //         userDB_id: user._id,
            //         amount: request_amount,
            //         before_wallet: user_before_wallet_balance || 0,
            //         tx_request_number: tx_request_number,
            //         transaction_type: 2,
            //         transaction_note: `Auto Withdraw via DollarBazar Payout`,
            //         utr: payout.utr,
            //         status: "SUCCESS"
            //     });



            //     record.fund_status = 1;
            //     record.payment_method = 7;
            //     record.utr = payout.utr;
            //     record.remark = remark;
            //     await record.save();

            // } else {
            //     console.log("🚀 (((((((((((((((((  PROTON PAY   )))))))))))))))))")
            // }


            // WITH THIS:
            if (autoWithdrawViaPG === 7 || autoWithdrawViaPG === 8) {
                console.log(`🚀 AUTO WITH ${autoWithdrawViaPG === 7 ? 'DOLLAR BAZAR' : 'PROTON PAY'} inside done `);

                const withdraw_reqDB_id = newRequest?._id;
                const remark = "Auto approve withdrawal request";

                // Use PayoutManager
                const payoutManager = require('../services/payoutManager');
                
                const payout = await payoutManager.processPayout(
                    request_amount,
                    bankDetails,
                    tx_request_number,
                    autoWithdrawViaPG
                );

                console.log("Auto Payout Result:", payout);

                const record = await withdraw_fund_request_module.findById(withdraw_reqDB_id);

                if (payout.status === "FAILED") {
                    record.fund_status = 2;
                    record.remark = payout.message;
                    await record.save();

                    return res.json({
                        success: false,
                        msg: `Payout Failed: ${payout.message}`,
                    });
                }

                // SUCCESS
                user.wallet_balance -= request_amount;
                await user.save();

                const adminData = await admin_module.findOneAndUpdate(
                    { admin_type: 0 }, 
                    { $inc: { wallet_amount: request_amount } }
                );

                // Get UTR
                let utr = "";
                if (autoWithdrawViaPG === 7) {
                    utr = payout.utr || payout.tnxId || "";
                } else if (autoWithdrawViaPG === 8) {
                    utr = payout.payoutId || "";
                }

                await wallet_trans_history_module.create({
                    userDB_id: user._id,
                    amount: request_amount,
                    before_wallet: user_before_wallet_balance || 0,
                    tx_request_number: tx_request_number,
                    transaction_type: 2,
                    transaction_note: `Auto Withdraw via ${autoWithdrawViaPG === 7 ? 'DollarBazar' : 'ProtonPay'} Payout`,
                    utr: utr,
                    status: "SUCCESS"
                });

                record.fund_status = 1;
                record.payment_method = autoWithdrawViaPG;
                record.utr = utr;
                if (autoWithdrawViaPG === 8) {
                    record.bankReference = payout.payoutId || "";
                }
                record.remark = remark;
                await record.save();

                return res.json({
                    success: true,
                    msg: 'Withdraw request auto-approved and processed successfully.',
                    fund_request_id: newRequest._id,
                });
            }



        }


        return res.json({
            success: true,
            msg: 'Withdraw request submitted successfully',
            fund_request_id: newRequest._id,
        });

    } catch (err) {
        console.error('Error in apiUserWithdrawFundRequest:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
}












// middleware not used for JWT token
const apiStarlineGameRates = async (req, res) => {
    try {
        let { app_key = '', env_type = '' } = req?.body || {};

        app_key = toStr(app_key);
        env_type = toStr(env_type);

        if (!app_key || !env_type) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res.status(401).json({ success: false, msg: 'UnAuthorized request' });
        }

        const rates = await starline_game_rates_module.findOne().lean();

        return res.json({
            success: true,
            game_rates: [rates][0],
            msg: 'Game Rates',
        });
    } catch (err) {
        console.error('apiStarlineGameRates error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};


// const apiStarlineGame = async (req, res) => {
//     try {
//         let { app_key = '', env_type = '' } = req?.body || {};

//         app_key = toStr(app_key);
//         env_type = toStr(env_type);

//         if (!app_key || !env_type) {
//             return res.status(400).json({ success: false, msg: 'All fields are required.' });
//         }

//         if (!checkRequestAuth(app_key, env_type)) {
//             return res.status(401).json({ success: false, msg: 'UnAuthorized request' });
//         }

//         const todayIST = moment_timeZone().tz('Asia/Kolkata').format('YYYY-MM-DD');
//         const nowIST = moment_timeZone.tz('Asia/Kolkata');
//         const currentDayName = getWeekdayNameInIST(new Date()).toLowerCase();

//         // Define today 00:00 and tomorrow 00:00 in IST
//         const todayStart = moment_timeZone().tz('Asia/Kolkata').startOf('day').toDate();
//         const tomorrowStart = moment_timeZone().tz('Asia/Kolkata').add(1, 'day').startOf('day').toDate();

//         const raw = await starline_games_module.aggregate([
//             { $match: { status: 1 } },

//             // Step 1: Get ONLY results declared TODAY based on open_decleare_date
//             {
//                 $lookup: {
//                     from: "starline_game_result_histories",
//                     let: { gameId: "$_id" },
//                     pipeline: [
//                         {
//                             $match: {
//                                 $expr: {
//                                     $and: [
//                                         { $eq: ["$gameDB_id", "$$gameId"] },
//                                         { $eq: ["$open_decleare_status", 1] },
//                                         { $gte: ["$result_date", todayStart] },
//                                         { $lt: ["$result_date", tomorrowStart] }
//                                     ]
//                                 }
//                             }
//                         },
//                         { $sort: { open_decleare_date: -1 } },
//                         { $limit: 1 }
//                     ],
//                     as: "todayDeclaredResult"
//                 }
//             },
//             { $unwind: { path: "$todayDeclaredResult", preserveNullAndEmptyArrays: true } },

//             // Step 2: Get today's timing
//             {
//                 $lookup: {
//                     from: "weekday_games",
//                     let: { gameId: "$_id" },
//                     pipeline: [
//                         {
//                             $match: {
//                                 $expr: {
//                                     $and: [
//                                         { $eq: ["$gameDB_id", "$$gameId"] },
//                                         { $eq: ["$week_name", currentDayName] }
//                                     ]
//                                 }
//                             }
//                         }
//                     ],
//                     as: "dayTiming"
//                 }
//             },
//             { $unwind: { path: "$dayTiming", preserveNullAndEmptyArrays: true } },

//             // Step 3: Format time + conditionally set open_number
//             {
//                 $addFields: {
//                     open_time_24: {
//                         $dateToString: {
//                             format: "%H:%M",
//                             date: "$dayTiming.open_time",
//                             timezone: "+05:30"
//                         }
//                     },
//                     market_status: { $ifNull: ["$dayTiming.weekday_status", 1] },

//                     // Only show number if declared today
//                     declared_open_number: {
//                         $cond: [
//                             { $ne: ["$todayDeclaredResult", null] },
//                             "$todayDeclaredResult.open_number",
//                             null
//                         ]
//                     }
//                 }
//             },

//             // Convert time to minutes for sorting
//             {
//                 $addFields: {
//                     sort_minutes: {
//                         $cond: [
//                             { $eq: ["$open_time_24", null] },
//                             9999,
//                             {
//                                 $add: [
//                                     { $multiply: [{ $toInt: { $substr: ["$open_time_24", 0, 2] } }, 60] },
//                                     { $toInt: { $substr: ["$open_time_24", 3, 2] } }
//                                 ]
//                             }
//                         ]
//                     }
//                 }
//             },

//             { $sort: { sort_minutes: 1 } },

//             // Final projection
//             {
//                 $project: {
//                     _id: 1,
//                     game_name: 1,
//                     open_time_24: 1,
//                     market_status: 1,
//                     declared_open_number: 1
//                 }
//             }
//         ]);

//         // Format response with proper logic
//         const result = raw.map(item => {
//             let open_time = "";
//             let msg = "Market closed";
//             let msg_status = 2;

//             if (item.open_time_24 && item.market_status === 1) {
//                 open_time = moment_timeZone(item.open_time_24, "HH:mm")
//                     .tz('Asia/Kolkata')
//                     .format('hh:mm A');

//                 const marketDateTime = moment_timeZone.tz(
//                     `${todayIST} ${item.open_time_24}`,
//                     'YYYY-MM-DD HH:mm',
//                     'Asia/Kolkata'
//                 );

//                 if (nowIST.isBefore(marketDateTime)) {
//                     msg = "Market is open";
//                     msg_status = 1;
//                 } else {
//                     msg = "Market is close";
//                     msg_status = 0;
//                 }
//             }

//             let open_result = "";
//             if (item.declared_open_number && item.declared_open_number !== "000") {
//                 const numStr = String(item.declared_open_number).padStart(3, '0');
//                 const digits = numStr.split('').map(Number);
//                 const sum = digits.reduce((a, b) => a + b, 0);
//                 const lastDigit = sum % 10;
//                 open_result = `${numStr}-${lastDigit}`;
//             }
//             // If not declared today → open_result remains "" → frontend shows ***

//             return {
//                 _id: item._id,
//                 game_name: item.game_name,
//                 open_time,
//                 msg,
//                 msg_status,
//                 open_result  // "" = not declared, "123-9" = declared today
//             };
//         });

//         if (!process.env.BASE_URL) {
//             return res.json({ success: false, msg: 'Base URL not set in environment variables' });
//         }

//         return res.json({
//             success: true,
//             msg: 'Starline Game Data',
//             web_starline_chart_url: `${process.env.BASE_URL}/game-result-chart-details`,
//             result
//         });

//     } catch (err) {
//         console.error('apiStarlineGame error:', err);
//         return res.status(500).json({ success: false, msg: 'Internal Server Error' });
//     }
// };



// bidsubmit


// 



// fixed open time issue

const apiStarlineGame = async (req, res) => {
    try {
        let { app_key = '', env_type = '' } = req?.body || {};

        app_key = toStr(app_key);
        env_type = toStr(env_type);

        if (!app_key || !env_type) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res.status(401).json({ success: false, msg: 'UnAuthorized request' });
        }

        const todayIST = moment_timeZone().tz('Asia/Kolkata').format('YYYY-MM-DD');
        const nowIST = moment_timeZone().tz('Asia/Kolkata');
        const currentDayName = getWeekdayNameInIST(new Date()).toLowerCase();

        // Define today 00:00 and tomorrow 00:00 in IST
        const todayStart = moment_timeZone().tz('Asia/Kolkata').startOf('day').toDate();
        const tomorrowStart = moment_timeZone().tz('Asia/Kolkata').add(1, 'day').startOf('day').toDate();

        const raw = await starline_games_module.aggregate([
            { $match: { status: 1 } },

            // Step 1: Get ONLY results declared TODAY based on open_decleare_date
            {
                $lookup: {
                    from: "starline_game_result_histories",
                    let: { gameId: "$_id" },
                    pipeline: [
                        {
                            $match: {
                                $expr: {
                                    $and: [
                                        { $eq: ["$gameDB_id", "$$gameId"] },
                                        { $eq: ["$open_decleare_status", 1] },
                                        { $gte: ["$result_date", todayStart] },
                                        { $lt: ["$result_date", tomorrowStart] }
                                    ]
                                }
                            }
                        },
                        { $sort: { open_decleare_date: -1 } },
                        { $limit: 1 }
                    ],
                    as: "todayDeclaredResult"
                }
            },
            { $unwind: { path: "$todayDeclaredResult", preserveNullAndEmptyArrays: true } },

            // Step 2: Get today's timing
            {
                $lookup: {
                    from: "weekday_games",
                    let: { gameId: "$_id" },
                    pipeline: [
                        {
                            $match: {
                                $expr: {
                                    $and: [
                                        { $eq: ["$gameDB_id", "$$gameId"] },
                                        { $eq: ["$week_name", currentDayName] }
                                    ]
                                }
                            }
                        }
                    ],
                    as: "dayTiming"
                }
            },
            { $unwind: { path: "$dayTiming", preserveNullAndEmptyArrays: true } },

            // Step 3: Format time + conditionally set open_number
            {
                $addFields: {
                    // Use the same function as admin API
                    open_time_ist: {
                        $cond: [
                            { $ne: ["$dayTiming.open_time", null] },
                            "$dayTiming.open_time",
                            null
                        ]
                    },
                    market_status: { $ifNull: ["$dayTiming.weekday_status", 1] },

                    // Only show number if declared today
                    declared_open_number: {
                        $cond: [
                            { $ne: ["$todayDeclaredResult", null] },
                            "$todayDeclaredResult.open_number",
                            null
                        ]
                    }
                }
            },

            // Convert time to minutes for sorting
            {
                $addFields: {
                    sort_minutes: {
                        $cond: [
                            { $eq: ["$open_time_ist", null] },
                            9999,
                            {
                                $hour: { $dateFromString: { dateString: { $toString: "$open_time_ist" } } }
                            }
                        ]
                    }
                }
            },

            { $sort: { sort_minutes: 1 } },

            // Final projection
            {
                $project: {
                    _id: 1,
                    game_name: 1,
                    open_time_ist: 1,
                    market_status: 1,
                    declared_open_number: 1
                }
            }
        ]);

        // Format response with proper logic
        const result = raw.map(item => {
            let open_time = "";
            let msg = "Market closed";
            let msg_status = 2;

            if (item.open_time_ist && item.market_status === 1) {
                // Use the same function as admin API
                open_time = get12HoursTimeFromISO(item.open_time_ist);

                // Create market date-time in IST
                const marketDateTime = moment_timeZone(item.open_time_ist).tz('Asia/Kolkata');
                const marketDateStr = marketDateTime.format('YYYY-MM-DD');
                const marketTimeStr = marketDateTime.format('HH:mm');

                const marketFullDateTime = moment_timeZone.tz(
                    `${marketDateStr} ${marketTimeStr}`,
                    'YYYY-MM-DD HH:mm',
                    'Asia/Kolkata'
                );

                if (nowIST.isBefore(marketFullDateTime)) {
                    msg = "Market is open";
                    msg_status = 1;
                } else {
                    msg = "Market is close";
                    msg_status = 0;
                }
            }

            let open_result = "";
            if (item.declared_open_number && item.declared_open_number !== "000") {
                const numStr = String(item.declared_open_number).padStart(3, '0');
                const digits = numStr.split('').map(Number);
                const sum = digits.reduce((a, b) => a + b, 0);
                const lastDigit = sum % 10;
                open_result = `${numStr}-${lastDigit}`;
            }
            // If not declared today → open_result remains "" → frontend shows ***

            return {
                _id: item._id,
                game_name: item.game_name,
                open_time,
                msg,
                msg_status,
                open_result  // "" = not declared, "123-9" = declared today
            };
        });

        if (!process.env.BASE_URL) {
            return res.json({ success: false, msg: 'Base URL not set in environment variables' });
        }

        return res.json({
            success: true,
            msg: 'Starline Game Data',
            web_starline_chart_url: `${process.env.BASE_URL}/game-result-chart-details`,
            result
        });

    } catch (err) {
        console.error('apiStarlineGame error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};







const apiStarlineSubmitBid = async (req, res) => {
    try {

        console.log("starline bit submit called");

        let { new_result = "" } = req?.body || {};

        if (!new_result) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        const userData = req?.user || null;
        // console.log("🚀 ~ apiStarlineSubmitBid ~ userData:", userData)
        if (!userData) {
            return res.status(404).json({ success: false, msg: "User not found" });
        }

        let {
            gameDB_id = "",
            Gamename: game_name = "",
            pana = "",
            bid_date = "",
            totalbit = "",
            result: bid_result = []
        } = new_result;

        gameDB_id = toStr(gameDB_id);
        game_name = toStr(game_name);
        pana = toStr(pana);
        bid_date = toStr(bid_date); // ex: "2025-Jul-21"
        totalbit = Number(toStr(totalbit));

        if (!gameDB_id || !game_name || !pana || !bid_date || !totalbit || !bid_result) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        if (!mongoose.isValidObjectId(gameDB_id)) {
            return res.status(400).json({ success: false, msg: "Invalid ID" });
        }

        const game = await starline_games_module.findOne({ _id: gameDB_id });
        console.log("gammee-", gameDB_id, game)
        if (!game) {
            return res.json({ success: false, msg: 'Game not found' });
        }

        const dayName = getWeekdayNameInIST();

        const filter = {
            gameDB_id,
            week_name: dayName.toLowerCase()
        };

        console.log(`(((((((()))))) ~ mobileController.js:3502 ~ apiStarlineSubmitBid ~ filter:`, filter);
        let schedule = null;
        try {
            schedule = await weekday_games_module.findOne(filter).lean();
            console.log("Schedule found:", schedule);
        } catch (err) {
            console.error("Error while fetching schedule:", err);
            // handle gracefully, maybe send a response
        }

        console.log(`(((((((()))))) ~ mobileController.js:3495 ~ apiStarlineSubmitBid ~ schedule:`, schedule);

        if (!schedule || schedule.weekday_status === 0) {
            return res.json({ success: false, msg: 'Sorry Betting Is Closed', game_status: 2 });
        }

        const { game_status, msg } = checkGameOpenStatus(schedule.open_time);
        if (game_status !== 1) {
            return res.json({ success: false, msg });
        }

        const gameRates = await starline_game_rates_module.findOne({});
        if (!gameRates) {
            return res.json({ success: false, msg: 'Unable to fetch game rates. Please try again.' });
        }

        schedule.open_time = moment_timeZone(schedule.open_time).tz('Asia/Kolkata').format('hh:mm A');

        const bidList = [];
        const walletTransactionList = [];
        let totalDeducted = 0;
        let userWalletBefore = userData?.wallet_balance;

        const mainAdmin = await admin_module.findOne({ admin_type: 0 }).lean();
        console.log("🚀 ~ apiSubmitBid ~ mainAdmin:", mainAdmin)

        for (const entry of bid_result) {
            const { session, digits, closedigits, points, pana: entryPana } = entry;

            if (totalbit < 0) {
                return res.json({ success: false, msg: 'Sorry something went wrong' });
            }

            if (userData.wallet_balance < totalbit) {
                return res.json({
                    success: false,
                    msg: "Sorry You Don't Have Sufficient Amount For This Bid",
                });
            }

            const actualPana = ['SP, DP, TP', 'SP DP TP', 'SP DP', 'SP TP', 'DP TP'].includes(pana)
                ? entryPana
                : pana;


            const pointsNum = Number(points);
            if (isNaN(pointsNum)) {
                console.log(`❌ Invalid points value: ${points}`);
                return res.json({
                    success: false,
                    msg: 'Invalid points value in bid entry.'
                });
            }

            let winAmt = 0;
            switch (actualPana) {
                case 'Single Digit':
                    winAmt = (gameRates.single_digit_val_2 / gameRates.single_digit_val_1) * points;
                    break;
                case 'Triple Pana':
                    winAmt = (gameRates.tripple_pana_val_2 / gameRates.tripple_pana_val_1) * points;
                    break;
                case 'Double Pana':
                    winAmt = (gameRates.double_pana_val_2 / gameRates.double_pana_val_1) * points;
                    break;
                case 'Single Pana':
                    winAmt = (gameRates.single_pana_val_2 / gameRates.single_pana_val_1) * points;
                    break;
            }

            const bid_tx_id = getUserRandomToken(10);
            const bidDateIST = moment_timeZone.tz(bid_date, "YYYY-MMM-DD", "Asia/Kolkata").toDate();

            bidList.push({
                userDB_id: userData._id,
                gameDB_id,
                game_name,
                pana: actualPana,
                session,
                digits,
                closedigits,
                points: pointsNum,
                winning_points: winAmt,
                bid_date: bidDateIST,
                bid_tx_id,
                pay_status: 0
            });

            walletTransactionList.push({
                userDB_id: userData._id,
                starline_gameDB_id: gameDB_id,
                before_wallet: userWalletBefore,
                amount: pointsNum,
                transaction_type: 2,
                transaction_note: `Bid Placed For ${game_name} on (${digits})`,
                amount_status: 5,
                tx_request_number: bid_tx_id,
                admin_name: mainAdmin?.username,
                admin_type: 0
            });

            totalDeducted += pointsNum;

            userWalletBefore -= pointsNum;
        }

        // FIX 3: Compare numbers properly
        // console.log(`💰 Amount check: frontend total=${totalbit}, calculated=${totalDeducted}`);
        if (totalDeducted !== totalbit) {
            // console.log(`⚠️ Amount mismatch: frontend sent ${totalbit} (type: ${typeof totalbit}), calculated ${totalDeducted} (type: ${typeof totalDeducted})`);
            return res.json({
                success: false,
                msg: `Bid amount calculation mismatch. Expected: ${totalbit}, Calculated: ${totalDeducted}. Please try again.`
            });
        }


        // Insert all at once
        await starline_bid_history_module.insertMany(bidList);
        await wallet_trans_history_module.insertMany(walletTransactionList);


        // Deduct wallet balance once
        userData.wallet_balance -= totalbit;
        await userData.save();



        // add bid amount to the main admin wallet account
        await admin_module.findOneAndUpdate({ admin_type: 0 }, { $inc: { wallet_amount: totalDeducted } }, { new: true });

        return res.json({
            success: true,
            msg: 'Bid Successfully Submitted',
            // transaction_id: bid_tx_id,
            new_balance: userData.wallet_balance
        });

    } catch (err) {
        console.error('apiStarlineSubmitBid error:', err);
        return res.status(500).json({ success: false, msg: `Internal Server Error - ${err}` });
    }
};


// fixed gali disswar open time issue
// fixed the open time issue

const apiGaliDisswarGame = async (req, res) => {
    try {
        let { app_key = '', env_type = '' } = req?.body || {};

        app_key = toStr(app_key);
        env_type = toStr(env_type);

        if (!app_key || !env_type) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res.status(401).json({ success: false, msg: 'UnAuthorized request' });
        }

        const todayIST = moment_timeZone().tz('Asia/Kolkata').format('YYYY-MM-DD');
        const nowIST = moment_timeZone.tz('Asia/Kolkata');
        const currentDayName = getWeekdayNameInIST(new Date()).toLowerCase();

        // Define today 00:00 and tomorrow 00:00 in IST
        const todayStart = moment_timeZone().tz('Asia/Kolkata').startOf('day').toDate();
        const tomorrowStart = moment_timeZone().tz('Asia/Kolkata').add(1, 'day').startOf('day').toDate();

        const raw = await gali_disswar_games_module.aggregate([
            { $match: { status: 1 } },

            // Step 1: Get ONLY result declared TODAY (based on close_decleare_date)
            {
                $lookup: {
                    from: "gali_disswar_game_result_histories",
                    let: { gameId: "$_id" },
                    pipeline: [
                        {
                            $match: {
                                $expr: {
                                    $and: [
                                        { $eq: ["$gameDB_id", "$$gameId"] },
                                        { $eq: ["$close_decleare_status", 1] },           // Must be declared
                                        { $gte: ["$close_decleare_date", todayStart] },   // Declared today
                                        { $lt: ["$close_decleare_date", tomorrowStart] }
                                    ]
                                }
                            }
                        },
                        { $sort: { close_decleare_date: -1 } },
                        { $limit: 1 }
                    ],
                    as: "todayDeclaredResult"
                }
            },
            { $unwind: { path: "$todayDeclaredResult", preserveNullAndEmptyArrays: true } },

            // Step 2: Get today's timing from weekday_games (including close_time)
            {
                $lookup: {
                    from: "weekday_games",
                    let: { gameId: "$_id" },
                    pipeline: [
                        {
                            $match: {
                                $expr: {
                                    $and: [
                                        { $eq: ["$gameDB_id", "$$gameId"] },
                                        { $eq: [{ $toLower: "$week_name" }, currentDayName] }
                                    ]
                                }
                            }
                        }
                    ],
                    as: "dayTiming"
                }
            },
            { $unwind: { path: "$dayTiming", preserveNullAndEmptyArrays: true } },

            // Step 3: Format time + conditionally set result (NO subtraction here - handled in get12HoursTimeFromISO like starline)
            {
                $addFields: {
                    open_time_ist: {
                        $cond: [
                            { $ne: ["$dayTiming.open_time", null] },
                            "$dayTiming.open_time",
                            null
                        ]
                    },
                    close_time: "$dayTiming.close_time",  // Add close for status logic
                    market_status: { $ifNull: ["$dayTiming.weekday_status", 1] },

                    // Only show result if declared today
                    declared_number: {
                        $cond: [
                            { $ne: ["$todayDeclaredResult", null] },
                            "$todayDeclaredResult.close_number",
                            null
                        ]
                    }
                }
            },

            // Convert time to minutes for sorting (use open_time_ist)
            {
                $addFields: {
                    sort_minutes: {
                        $cond: [
                            { $eq: ["$open_time_ist", null] },
                            9999,
                            {
                                $add: [
                                    { $multiply: [{ $convert: { input: { $substr: [{ $dateToString: { format: "%H:%M", date: "$open_time_ist", timezone: "+05:30" } }, 0, 2] }, to: "int", onError: 0 } }, 60] },
                                    { $convert: { input: { $substr: [{ $dateToString: { format: "%H:%M", date: "$open_time_ist", timezone: "+05:30" } }, 3, 2] }, to: "int", onError: 0 } }
                                ]
                            }
                        ]
                    }
                }
            },

            { $sort: { sort_minutes: 1 } },

            // Final clean output
            {
                $project: {
                    _id: 1,
                    game_name: 1,
                    open_time_ist: 1,  // Pass original for get12HoursTimeFromISO
                    close_time: 1,
                    market_status: 1,
                    declared_number: 1
                }
            }
        ]);

        // Format final response - Match starline exactly
        const result = raw.map(item => {
            let open_time = "";
            let msg = "Market Closed";  // Default to match admin/starline
            let msg_status = 2;

            if (item.open_time_ist && item.market_status === 1) {
                // Use the same function as starline/admin for consistent formatting (handles pre-open internally)
                open_time = get12HoursTimeFromISO(item.open_time_ist);

                // Create market date-time in IST
                const marketDateTime = moment_timeZone(item.open_time_ist).tz('Asia/Kolkata');
                const marketDateStr = marketDateTime.format('YYYY-MM-DD');
                const marketTimeStr = marketDateTime.format('HH:mm');

                const marketFullDateTime = moment_timeZone.tz(
                    `${marketDateStr} ${marketTimeStr}:00`,  // Add seconds
                    'YYYY-MM-DD HH:mm:ss',
                    'Asia/Kolkata'
                );

                // Add close_time logic for accurate status
                let closeFullDateTime;
                if (item.close_time) {
                    const closeDateTime = moment_timeZone(item.close_time).tz('Asia/Kolkata');
                    const closeDateStr = closeDateTime.format('YYYY-MM-DD');
                    const closeTimeStr = closeDateTime.format('HH:mm');
                    closeFullDateTime = moment_timeZone.tz(
                        `${closeDateStr} ${closeTimeStr}:00`,
                        'YYYY-MM-DD HH:mm:ss',
                        'Asia/Kolkata'
                    );
                }

                if (nowIST.isBefore(marketFullDateTime)) {
                    msg = "Market not yet open";
                    msg_status = 0;
                } else if (closeFullDateTime && nowIST.isBefore(closeFullDateTime)) {
                    msg = "Betting is running";
                    msg_status = 1;
                } else {
                    msg = "Market Closed";
                    msg_status = 2;
                }
            }

            let open_result = "";  // This will be the displayed result like "20" or ""
            if (item.declared_number && item.declared_number !== "000") {
                open_result = String(item.declared_number).padStart(2, '0');  // Ensures 04, 20, etc.
            }
            // If not declared today → open_result = "" → frontend shows ***

            return {
                _id: item._id,
                game_name: item.game_name,
                open_time,
                msg,
                msg_status,
                open_result   // "20", "04", or "" (not declared)
            };
        });

        if (!process.env.BASE_URL) {
            return res.json({ success: false, msg: 'Base URL not set in environment variables' });
        }

        return res.json({
            success: true,
            msg: 'Jackpot Game Data',
            web_galidessar_chart_url: `${process.env.BASE_URL}/game-result-galidessar-chart-details`,
            result
        });

    } catch (err) {
        console.error('apiGaliDisswarGame error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};


// const apiGaliDisswarGame = async (req, res) => {
//     try {
//         let { app_key = '', env_type = '' } = req?.body || {};

//         app_key = toStr(app_key);
//         env_type = toStr(env_type);

//         if (!app_key || !env_type) {
//             return res.status(400).json({ success: false, msg: 'All fields are required.' });
//         }

//         if (!checkRequestAuth(app_key, env_type)) {
//             return res.status(401).json({ success: false, msg: 'UnAuthorized request' });
//         }

//         const todayIST = moment_timeZone().tz('Asia/Kolkata').format('YYYY-MM-DD');
//         const nowIST = moment_timeZone.tz('Asia/Kolkata');
//         const currentDayName = getWeekdayNameInIST(new Date()).toLowerCase();

//         // Define today 00:00 and tomorrow 00:00 in IST
//         const todayStart = moment_timeZone().tz('Asia/Kolkata').startOf('day').toDate();
//         const tomorrowStart = moment_timeZone().tz('Asia/Kolkata').add(1, 'day').startOf('day').toDate();

//         const raw = await gali_disswar_games_module.aggregate([
//             { $match: { status: 1 } },

//             // Step 1: Get ONLY result declared TODAY (based on close_decleare_date)
//             {
//                 $lookup: {
//                     from: "gali_disswar_game_result_histories",
//                     let: { gameId: "$_id" },
//                     pipeline: [
//                         {
//                             $match: {
//                                 $expr: {
//                                     $and: [
//                                         { $eq: ["$gameDB_id", "$$gameId"] },
//                                         { $eq: ["$close_decleare_status", 1] },           // Must be declared
//                                         { $gte: ["$close_decleare_date", todayStart] },   // Declared today
//                                         { $lt: ["$close_decleare_date", tomorrowStart] }
//                                     ]
//                                 }
//                             }
//                         },
//                         { $sort: { close_decleare_date: -1 } },
//                         { $limit: 1 }
//                     ],
//                     as: "todayDeclaredResult"
//                 }
//             },
//             { $unwind: { path: "$todayDeclaredResult", preserveNullAndEmptyArrays: true } },

//             // Step 2: Get today's timing from weekday_games
//             {
//                 $lookup: {
//                     from: "weekday_games",
//                     let: { gameId: "$_id" },
//                     pipeline: [
//                         {
//                             $match: {
//                                 $expr: {
//                                     $and: [
//                                         { $eq: ["$gameDB_id", "$$gameId"] },
//                                         { $eq: [{ $toLower: "$week_name" }, currentDayName] }
//                                     ]
//                                 }
//                             }
//                         }
//                     ],
//                     as: "dayTiming"
//                 }
//             },
//             { $unwind: { path: "$dayTiming", preserveNullAndEmptyArrays: true } },

//             // Step 3: Format time + conditionally set result
//             {
//                 $addFields: {
//                     open_time_24: {
//                         $dateToString: {
//                             format: "%H:%M",
//                             date: "$dayTiming.open_time",
//                             timezone: "+05:30"
//                         }
//                     },
//                     market_status: { $ifNull: ["$dayTiming.weekday_status", 1] },

//                     // Only show result if declared today
//                     declared_number: {
//                         $cond: [
//                             { $ne: ["$todayDeclaredResult", null] },
//                             "$todayDeclaredResult.close_number",
//                             null
//                         ]
//                     }
//                 }
//             },

//             // Convert time to minutes for sorting
//             {
//                 $addFields: {
//                     sort_minutes: {
//                         $cond: [
//                             { $eq: ["$open_time_24", null] },
//                             9999,
//                             {
//                                 $add: [
//                                     { $multiply: [{ $toInt: { $substr: ["$open_time_24", 0, 2] } }, 60] },
//                                     { $toInt: { $substr: ["$open_time_24", 3, 2] } }
//                                 ]
//                             }
//                         ]
//                     }
//                 }
//             },

//             { $sort: { sort_minutes: 1 } },

//             // Final clean output
//             {
//                 $project: {
//                     _id: 1,
//                     game_name: 1,
//                     open_time_24: 1,
//                     market_status: 1,
//                     declared_number: 1
//                 }
//             }
//         ]);

//         // Format final response
//         const result = raw.map(r => {
//             let open_time = "";
//             let msg = "Market closed";
//             let msg_status = 2;

//             open_time = moment_timeZone(r.open_time_24, "HH:mm")
//                 .tz('Asia/Kolkata')
//                 .format('hh:mm A');
//             if (r.open_time_24 && r.market_status === 1) {

//                 const marketTime = moment_timeZone.tz(
//                     `${todayIST} ${r.open_time_24}`,
//                     'YYYY-MM-DD HH:mm',
//                     'Asia/Kolkata'
//                 );

//                 if (nowIST.isBefore(marketTime)) {
//                     msg = "Betting is running";
//                     msg_status = 1;
//                 } else {
//                     msg = "Market not yet open";
//                     msg_status = 0;
//                 }
//             }

//             let open_result = "";  // This will be the displayed result like "20" or ""
//             if (r.declared_number && r.declared_number !== "000") {
//                 open_result = String(r.declared_number).padStart(2, '0');  // Ensures 04, 20, etc.
//             }
//             // If not declared today → open_result = "" → frontend shows ***

//             return {
//                 _id: r._id,
//                 game_name: r.game_name,
//                 open_time,
//                 msg,
//                 msg_status,
//                 open_result   // "20", "04", or "" (not declared)
//             };
//         });

//         if (!process.env.BASE_URL) {
//             return res.json({ success: false, msg: 'Base URL not set in environment variables' });
//         }

//         return res.json({
//             success: true,
//             msg: 'Jackpot Game Data',
//             web_galidessar_chart_url: `${process.env.BASE_URL}/game-result-galidessar-chart-details`,
//             result
//         });

//     } catch (err) {
//         console.error('apiGaliDisswarGame error:', err);
//         return res.status(500).json({ success: false, msg: 'Internal Server Error' });
//     }
// };


// middleware not used for JWT token
const apiGaliDisswarGameRates = async (req, res) => {
    try {
        let { app_key = '', env_type = '' } = req?.body || {};

        app_key = toStr(app_key);
        env_type = toStr(env_type);

        if (!app_key || !env_type) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res.json({ success: false, msg: 'Unauthorized request' });
        }

        const result = await gali_disswar_game_rates_module.find().lean()

        if (result) {
            return res.json({
                success: true,
                game_rates: result[0],
                msg: 'Game Rates',
            });
        } else {
            return res.json({
                success: false,
                game_rates: [],
                msg: 'Game Rates Not Added Yet',
            });
        }
    } catch (err) {
        console.error('apiGaliDisswarGameRates error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

// bidsubmit
const apiGaliDisswarSubmitBid = async (req, res) => {
    try {

        let { new_result = "" } = req?.body || {};

        console.log(`(((((((()))))) ~ mobileController.js:3805 ~ apiGaliDisswarSubmitBid ~ new_result:`, new_result);

        if (!new_result) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        const userData = req?.user || null;
        if (!userData) {
            return res.status(404).json({ success: false, msg: "User not found" });
        }

        let {
            gameDB_id = "",
            Gamename: game_name = "",
            pana = "",
            bid_date = "",
            totalbit = "",
            result: bid_result = []
        } = new_result;

        gameDB_id = toStr(gameDB_id);
        game_name = toStr(game_name);
        pana = toStr(pana);
        bid_date = toStr(bid_date); // ex: "2025-Jul-21"
        totalbit = Number(toStr(totalbit));

        if (!gameDB_id || !game_name || !pana || !bid_date || !totalbit || !bid_result) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        if (!mongoose.isValidObjectId(gameDB_id)) {
            return res.status(400).json({ success: false, msg: "Invalid ID" });
        }

        const game = await gali_disswar_games_module.findOne({ _id: gameDB_id });

        console.log(`(((((((()))))) ~ mobileController.js:3838 ~ apiGaliDisswarSubmitBid ~ game:`, game);
        if (!game) {
            return res.json({ success: false, msg: 'Game not found' });
        }

        const dayName = getWeekdayNameInIST();

        const filter = {
            gameDB_id,
            week_name: dayName.toLowerCase()
        };

        console.log(`(((((((()))))) ~ mobileController.js:3856 ~ apiStarlineSubmitBid ~ filter:`, filter);

        let schedule = null;

        try {
            schedule = await weekday_games_module.findOne(filter).lean();
            console.log("Schedule found:", schedule);
        } catch (err) {
            console.error("Error while fetching schedule:", err);
            // handle gracefully, maybe send a response
        }


        if (!schedule || schedule.weekday_status === 0) {
            return res.json({ success: false, msg: 'Sorry Betting Is Closed', game_status: 2, weekday_status });
        }

        const { game_status, msg } = checkGameOpenStatus(schedule.open_time);
        if (game_status !== 1) {
            return res.json({ success: false, msg });
        }

        const gameRates = await gali_disswar_game_rates_module.findOne({});
        console.log("🚀 ~ apiGaliDisswarSubmitBid ~ gameRates:", gameRates)
        if (!gameRates) {
            return res.json({ success: false, msg: 'Unable to fetch game rates. Please try again.' });
        }

        schedule.open_time = moment_timeZone(schedule.open_time).tz('Asia/Kolkata').format('hh:mm A');

        const bidList = [];
        const walletTransactionList = [];
        let totalDeducted = 0;
        let currentUserWalletBalance = userData?.wallet_balance;

        const result = await gali_disswar_game_rates_module.findOne().lean()

        const mainAdmin = await admin_module.findOne({ admin_type: 0 }).lean();
        console.log("🚀 ~ apiSubmitBid ~ mainAdmin:", mainAdmin)



        for (const entry of bid_result) {
            const { session, digits, closedigits, points } = entry;

            if (totalbit < 0) {
                return res.json({ success: false, msg: 'Sorry something went wrong' });
            }

            if (userData.wallet_balance < totalbit) {
                return res.json({
                    success: false,
                    msg: "Sorry You Don't Have Sufficient Amount For This Bid",
                });
            }

            const actualPana = pana

            let winAmt = 0;
            switch (actualPana) {
                case 'Group Jodi':
                    winAmt = (result.group_jodi_val_2 / result.group_jodi_val_1) * points;
                    break;
                case 'Red Bracket':
                    winAmt = (result.red_bracket_val_2 / result.red_bracket_val_1) * points;
                    break;
                case 'Jodi Digit':
                    winAmt = (result.jodi_digit_val_2 / result.jodi_digit_val_1) * points;
                    console.log("🚀 ~ apiGaliDisswarSubmitBid ~ points:", points)
                    console.log("🚀 ~ apiGaliDisswarSubmitBid ~ result.jodi_digit_val_1:", result.jodi_digit_val_1)
                    console.log("🚀 ~ apiGaliDisswarSubmitBid ~ result.jodi_digit_val_2:", result.jodi_digit_val_2)
                    console.log("🚀 ~ apiGaliDisswarSubmitBid ~ winAmt:", winAmt)
                    break;
            }

            const bid_tx_id = getUserRandomToken();
            const bidDateIST = moment_timeZone.tz(bid_date, "YYYY-MMM-DD", "Asia/Kolkata").toDate();

            bidList.push({
                userDB_id: userData._id,
                gameDB_id,
                game_name,
                pana: actualPana,
                session,
                digits,
                closedigits,
                points,
                winning_points: winAmt,
                bid_date: bidDateIST,
                bid_tx_id,
                pay_status: 0
            });

            walletTransactionList.push({
                userDB_id: userData._id,
                jackpot_gameDB_id: gameDB_id,
                amount: points,
                before_wallet: currentUserWalletBalance,
                transaction_type: 2,
                transaction_note: `Bid Placed For ${game_name} on (${digits})`,
                amount_status: 5,
                tx_request_number: bid_tx_id,
                admin_name: mainAdmin?.username,
                admin_type: 0
            });

            totalDeducted += points;

            currentUserWalletBalance -= points;
            console.log(`💰 Deducting points: ${points}, New Balance: ${currentUserWalletBalance}`);
        }

        // Deduct wallet balance once
        userData.wallet_balance -= totalDeducted;
        await userData.save();

        // add bid amount to the main admin wallet account
        await admin_module.findOneAndUpdate({ admin_type: 0 }, { $inc: { wallet_amount: totalDeducted } }, { new: true });


        // Insert all at once
        await gali_disswar_bid_history_module.insertMany(bidList);
        await wallet_trans_history_module.insertMany(walletTransactionList);

        return res.json({ success: true, msg: 'All Bids Successfully Submitted' });
    } catch (err) {
        console.error('apiGaliDisswarSubmitBid error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};


// middleware not used for JWT token
const apiGetState = async (req, res) => {
    try {
        let { app_key = "", env_type = "" } = req?.body || {};
        s
        app_key = toStr(app_key);
        env_type = toStr(env_type);

        if (!app_key || !env_type) {
            return res
                .status(400)
                .json({ success: false, msg: 'All fields are required.' });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res
                .status(401)
                .json({ success: false, msg: 'Unauthorized request.' });
        }

        const states = await state_module
            .find({ status: { $ne: 0 } })
            .lean();

        return res.json({
            success: states.length > 0,
            states
        });
    } catch (error) {
        console.error('Error in apiGetState:', error);
        return res
            .status(500)
            .json({ success: false, msg: 'Internal Server Error' });
    }
};

// middleware not used for JWT token
const apiGetDistrict = async (req, res) => {
    try {
        let { app_key, env_type, stateDB_id } = req.body;
        app_key = toStr(app_key);
        env_type = toStr(env_type);
        stateDB_id = toStr(stateDB_id);

        if (!app_key || !env_type || !stateDB_id) {
            return res
                .status(400)
                .json({ success: false, msg: 'All fields are required.' });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res
                .status(401)
                .json({ success: false, msg: 'Unauthorized request.' });
        }

        const districts = await district_module
            .find({ stateDB_id, status: { $ne: 0 } })
            .lean();

        return res.json({
            success: districts.length > 0,
            district: districts
        });
    } catch (error) {
        console.error('Error in apiGetDistrict:', error);
        return res
            .status(500)
            .json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiAddUserAddress = async (req, res) => {
    try {
        const {
            stateDB_id = "",
            districtDB_id = "",
            flat_ploat_no = "",
            address_lane_1 = "",
            address_lane_2 = "",
            area = "",
            pin_code = ""
        } = req?.body || {};

        if (
            !stateDB_id || !districtDB_id || !flat_ploat_no ||
            !address_lane_1 || !address_lane_2 || !area || !pin_code
        ) {
            return res.status(401).json({ success: false, msg: 'All fields are required.' });
        }

        const cleanedStateId = toStr(stateDB_id);
        const cleanedDistrictId = toStr(districtDB_id);
        const cleanedLane1 = toStr(address_lane_1);
        const cleanedLane2 = toStr(address_lane_2);
        const cleanedArea = toStr(area);
        const cleanedPincode = parseInt(pin_code);

        if (isNaN(cleanedPincode)) {
            return res.status(400).json({
                success: false,
                msg: 'Invalid pin code. Must be a number.'
            });
        }

        const userData = req?.user || null;
        if (!userData?._id) {
            return res.status(404).json({ success: false, msg: 'User not found' });
        }

        const [state, district] = await Promise.all([
            state_module.findOne({ _id: cleanedStateId, status: { $ne: 0 } }).lean(),
            district_module.findOne({ _id: cleanedDistrictId, status: { $ne: 0 } }).lean()
        ]);

        if (!state) {
            return res.status(400).json({ success: false, msg: 'Invalid state' });
        }

        if (!district) {
            return res.status(400).json({ success: false, msg: 'Invalid district' });
        }

        if (!mongoose.isValidObjectId(cleanedStateId) || !mongoose.isValidObjectId(cleanedDistrictId)) {
            return res.status(400).json({ success: false, msg: "Invalid ID" });
        }

        const addressData = {
            userDB_id: userData._id,
            flat_ploat_no: toStr(flat_ploat_no),
            address_lane_1: cleanedLane1,
            address_lane_2: cleanedLane2,
            area: cleanedArea,
            pin_code: cleanedPincode,
            stateDB_id: cleanedStateId,
            districtDB_id: cleanedDistrictId
        };

        const result = await user_address_module.findOneAndUpdate(
            { userDB_id: userData._id },
            { $set: addressData },
            { upsert: true, new: true }
        );

        const message = result.createdAt === result.updatedAt
            ? 'Your address has been successfully registered.'
            : 'Address updated successfully.';

        return res.json({ success: true, msg: message });

    } catch (error) {
        console.error('Error in apiAddUserAddress:', error);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiGetUserAddress = async (req, res) => {
    try {
        const { _id: userDB_id = "" } = req?.user || {};
        if (!userDB_id) {
            return res
                .status(401)
                .json({ success: false, msg: 'User not found' });
        }

        const address = await user_address_module
            .findOne({ userDB_id: mongoose.Types.ObjectId(userDB_id), status: { $ne: 0 } })
            .lean();

        if (!address) {
            return res
                .status(404)
                .json({
                    success: false,
                    user_address: {},
                    msg: 'Address Not Added Yet'
                });
        }

        const [state, district] = await Promise.all([
            state_module
                .findOne({ _id: address.stateDB_id, status: { $ne: 0 } })
                .lean(),
            district_module
                .findOne({ _id: address.districtDB_id, status: { $ne: 0 } })
                .lean()
        ]);

        if (!state) {
            return res
                .status(404)
                .json({
                    success: false,
                    user_address: {},
                    msg: 'Invalid state'
                });
        }
        if (!district) {
            return res
                .status(404)
                .json({
                    success: false,
                    user_address: {},
                    msg: 'Invalid district'
                });
        }

        const user_address = {
            state_name: state.state_name,
            district_name: district.district_name,
            stateDB_id: address.stateDB_id,
            districtDB_id: address.districtDB_id,
            flat_ploat_no: address.flat_ploat_no,
            address_lane_1: address.address_lane_1,
            address_lane_2: address.address_lane_2,
            area: address.area,
            pin_code: address.pin_code
        };

        return res.json({
            success: true,
            user_address,
            msg: 'User Address Detail'
        });

    } catch (error) {
        console.error('Error in apiGetUserAddress:', error);
        return res
            .status(500)
            .json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiGetProfile = async (req, res) => {
    try {
        let {
            _id: userDB_id = "",
            mobile = "",
            wallet_balance = "",
            username = "",
            user_name = "",
            my_code = ""
        } = req?.user || null;

        if (!userDB_id) {
            return res.status(404).json({ success: false, msg: 'User not found.' });
        }

        const payment_option = (await user_bank_details_module.findOne({ userDB_id })) || {};

        const profile = { mobile, wallet_balance, username, user_name, userDB_id, my_code };

        const msg = Object.keys(payment_option).length
            ? 'User Profile Data.'
            : 'Payment Option Not Added Yet';

        return res.json({ success: true, profile, payment_option, msg });
    } catch (error) {
        console.error('Error in apiGetProfile:', error);
        return res
            .status(500)
            .json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiProfileUpdate = async (req, res) => {
    try {
        let {
            user_name = "",
            username = "",
            paytm_number = "",
            google_pay_number = "",
            phone_pay_number = "",
            bank_name = "",
            branch_address = "",
            ac_holder_name = "",
            ac_number = "",
            ifsc_code = "",
        } = req?.body || {};

        const userData = req?.user || null;
        if (!userData) {
            return res.status(401).json({ success: false, msg: 'User not found.' });
        }

        const toStr = v => (v ? String(v).trim() : '');

        user_name = toStr(user_name);
        username = toStr(username);

        if (!user_name || !username) {
            return res.status(404).json({ success: false, msg: 'user_name and username are required.' });
        }

        const hasPayment = !!(paytm_number || google_pay_number || phone_pay_number);
        const hasBank = [bank_name, branch_address, ac_holder_name, ac_number, ifsc_code]
            .every(f => toStr(f));

        if (!hasPayment && !hasBank) {
            return res.status(400).json({
                success: false,
                msg: 'Provide at least one payment number or full bank details.'
            });
        }

        if (!userData?._id) {
            return res.status(401).json({ success: false, msg: 'User not found.' });
        }

        if (hasBank) {
            [bank_name, branch_address, ac_holder_name, ifsc_code] =
                [bank_name, branch_address, ac_holder_name, ifsc_code].map(toStr);
        }

        const usernameTaken = await user_module.exists({
            username,
            _id: { $ne: userData._id }
        });
        if (usernameTaken) {
            return res.json({ success: false, msg: 'This username already exists.' });
        }

        if (hasPayment) {
            const conflict = await user_bank_details_module.findOne({
                userDB_id: { $ne: userData._id },
                $or: [
                    { paytm_number },
                    { google_pay_number },
                    { phone_pay_number }
                ]
            }).lean();
            if (conflict) {
                return res.json({ success: false, msg: 'Payment number already in use.' });
            }
        }

        const formattedName = user_name.replace(/\s+/g, ' ')
            .replace(/\b\w/g, c => c.toUpperCase());
        const userUpdates = {
            user_name: formattedName,
            username,
        };

        let bankUpdates = hasBank
            ? {
                bank_name,
                branch_address,
                ac_holder_name,
                ac_number,
                ifsc_code
            }
            : null;

        bankUpdates = {
            ...(bankUpdates && { bankUpdates }),
            ...(paytm_number && { paytm_number }),
            ...(google_pay_number && { google_pay_number }),
            ...(phone_pay_number && { phone_pay_number }),
        }

        await Promise.all([
            user_module.updateOne({ _id: userData._id }, userUpdates),
            bankUpdates &&
            user_bank_details_module.updateOne(
                { userDB_id: userData._id },
                bankUpdates,
                { upsert: true }
            ),
        ]);

        return res.json({
            success: true,
            msg: 'Your profile was successfully updated.'
        });
    } catch (error) {
        console.error('Error in apiProfileUpdate:', error);
        return res
            .status(500)
            .json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiCheckSecurityPin = async (req, res) => {
    try {
        let { security_pin = "" } = req?.body || {};
        const userData = req?.user || null;

        security_pin = Number(toStr(security_pin));

        if (!userData || !userData._id) {
            return res.status(401).json({ success: false, msg: 'User not found' });
        }

        if (!security_pin) {
            return res.status(404).json({ success: false, msg: 'Security pin is required' });
        }

        const pinRegex = /^\d{4}$/;

        if (!pinRegex.test(security_pin)) {
            return res
                .status(400)
                .json({ success: false, msg: 'Security pin must be 4 digits.' });
        }

        if (Number(security_pin) === userData.security_pin) {
            return res.json({ success: true, msg: 'Security pin is correct' });
        } else {
            return res.json({ success: false, msg: 'Security pin is invalid' });
        }
    } catch (error) {
        console.error('Error in apiCheckSecurityPin:', error);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiFundRequestAdd = async (req, res) => {
    try {
        let { request_amount = "" } = req?.body || {};
        request_amount = toStr(request_amount);
        const userData = req?.user || null;

        if (!userData || !userData._id) {
            return res.status(401).json({ success: false, msg: 'User not found' });
        }

        if (!request_amount || isNaN(request_amount) || Number(request_amount) <= 0) {
            return res.status(400).json({ success: false, msg: 'Invalid request amount' });
        }

        const request_number = getUserRandomToken(6, true);

        const fundRequestData = {
            userDB_id: userData._id,
            request_amount: Number(request_amount),
            request_number,
        };

        const newFundRequest = await add_fund_request_module.create(fundRequestData);

        return res.json({
            success: true,
            msg: 'Request successfully added',
            fund_request_id: newFundRequest._id,
        });
    } catch (error) {
        console.error('Error in apiFundRequestAdd:', error);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiLastFundRequestDetail = async (req, res) => {
    try {
        const userData = req?.user || null;

        if (!userData || !userData._id) {
            return res.status(401).json({ success: false, msg: 'User not found' });
        }

        let lastRequest = await add_fund_request_module.findOne({
            userDB_id: userData._id
        }).lean();

        if (!process.env.MIN_DEPOSITE || !process.env.MAX_DEPOSITE) {
            return res.status(400).json({
                success: false,
                msg: 'Environment variables for MIN_DEPOSITE and MAX_DEPOSITE are not set'
            });
        }

        const response = {
            success: false,
            last_req_detail: [],
            min_amt: process.env.MIN_DEPOSITE,
            max_amt: process.env.MAX_DEPOSITE,
            google_upi_option: 1,
            phone_upi_option: 1,
            other_upi_option: 1,
        };

        if (lastRequest) {
            const formattedDate = formatDateToDDMMYYYY(lastRequest.insert_date)
            response.last_req_detail = {
                ...lastRequest,
                insert_date: formattedDate
            };
            response.success = true;
        }

        return res.json(response);

    } catch (error) {
        console.error('Error in apiLastFundRequestDetail:', error);
        return res.status(500).json({ msg: 'Internal Server Error', success: false });
    }
};

const apiFundPaymentSlipUpload = async (req, res) => {
    try {
        let { fund_requestDB_id = "" } = req?.body || {};

        fund_requestDB_id = toStr(fund_requestDB_id);

        if (!fund_requestDB_id) {
            return res.status(400).json({ success: false, msg: 'Fund Request DB ID Not Available' });
        }

        if (!req.file || !req.file.buffer) {
            return res.status(400).json({ success: false, msg: 'File type invalid or missing' });
        }

        const fileBuffer = req.file.buffer;

        const imageDB_id = await new file_module({
            fileInfo: {
                fileBuffer,
                content_type: req.file.mimetype,
            }
        })

        const update = await add_fund_request_module.findOneAndUpdate(
            { _id: fund_requestDB_id },
            {
                fund_payment_receipt: imageDB_id._id,
            },
            { new: true }
        );

        if (!update) {
            return res.status(404).json({ success: false, msg: 'Fund request not found' });
        }

        return res.json({
            success: true,
            msg: 'Payment Slip Uploaded Successfully.',
            request_status: update.request_status,
        });

    } catch (error) {
        console.error('Error in apiFundPaymentSlipUpload:', error);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiAddUserUpiDetails = async (req, res) => {
    try {
        const userData = req?.user || null;

        if (!userData || !userData._id) {
            return res.status(401).json({ success: false, msg: 'User not found' });
        }

        let { upi_type = "", paytm_number = "", google_pay_number = "", phone_pay_number = "" } = req?.body || {};

        upi_type = Number(toStr(upi_type));
        paytm_number = Number(toStr(paytm_number));
        google_pay_number = Number(toStr(google_pay_number));
        phone_pay_number = Number(toStr(phone_pay_number));

        if (!upi_type && !paytm_number && !google_pay_number && !phone_pay_number) {
            return res.status(400).json({ success: false, msg: 'At last One field required' });
        }

        if (![1, 2, 3].includes(upi_type)) {
            return res.status(400).json({ success: false, msg: 'This UPI Type Is Not Valid' });
        }

        const updateData = {};
        if (upi_type === 1 && paytm_number) {
            updateData.paytm_number = paytm_number;
        } else if (upi_type === 2 && google_pay_number) {
            updateData.google_pay_number = google_pay_number;
        } else if (upi_type === 3 && phone_pay_number) {
            updateData.phone_pay_number = phone_pay_number;
        } else {
            return res.status(400).json({ success: false, msg: 'Invalid field' });
        }

        const existing = await user_bank_details_module.findOne({ userDB_id: userData._id }).lean();

        if (existing) {
            await user_bank_details_module.updateOne({ userDB_id: userData._id }, { $set: updateData });
            return res.json({
                success: true,
                msg:
                    upi_type === 1
                        ? 'Paytm Number updated successfully.'
                        : upi_type === 2
                            ? 'Google Pay Number updated successfully.'
                            : 'Phone Pay Number updated successfully.',
            });
        } else {
            const newData = {
                userDB_id: userData._id,
                ...updateData
            };
            await user_bank_details_module.create(newData);
            return res.json({
                success: true,
                msg:
                    upi_type === 1
                        ? 'Paytm Number successfully registered.'
                        : upi_type === 2
                            ? 'Google Pay Number successfully registered.'
                            : 'Phone Pay Number successfully registered.',
            });
        }
    } catch (error) {
        console.error('Error in apiAddUserUpiDetails:', error);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiGetUserPaymentDetails = async (req, res) => {
    try {
        const userData = req?.user || null;

        if (!userData || !userData._id) {
            return res.status(401).json({ success: false, msg: 'User not found' });
        }

        const result = await user_bank_details_module.findOne(
            { userDB_id: userData._id }
        ).lean();

        if (result) {
            return res.json({
                success: true,
                payment_details: result,
                msg: 'User Payment Detail',
            });
        } else {
            return res.json({
                success: false,
                payment_details: null,
                msg: 'Payment Detail Not Added Yet',
            });
        }
    } catch (error) {
        console.error('Error in apiGetUserPaymentDetails:', error);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiGameRates = async (req, res) => {
    try {
        const userData = req?.user || null;

        if (!userData || !userData._id) {
            return res.status(401).json({ success: false, msg: 'User not found' });
        }
        const result = await game_rates_module.find().lean();

        if (!result) {
            return res.status(404).json({ success: false, msg: 'No game rates found' });
        }

        if (result) {
            return res.json({
                success: true,
                game_rates: result?.[0],
                msg: 'Game Rates',
            });
        } else {
            return res.status(404).json({
                success: false,
                game_rates: {},
                msg: 'Game rates have not been added yet.'
            });
        }
    } catch (error) {
        console.error('Error in apiGameRates:', error);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiFundRequestHistory = async (req, res) => {
    try {
        const baseUrl = process?.env?.BASE_URL;
        if (!baseUrl) {
            return res.status(500).json({ success: false, msg: "Base URL not set" });
        }

        let { status = "" } = req?.body || {};
        status = Number(toStr(status));
        const userData = req?.user || null;

        let query = { userDB_id: userData._id };
        if (status && status !== '') {
            query.request_status = status;
        }

        const results = await add_fund_request_module.find(query).lean();

        const formattedResults = results.map(item => {
            let receiptUrl = '';
            if (item?.fund_payment_receipt) {
                receiptUrl = `${baseUrl}/file/uploads/images/${item?.fund_payment_receipt?.toString()}`;
            }

            return {
                fund_request_id: item._id,
                request_amount: item.request_amount,
                request_number: item.request_number,
                request_status: item.request_status,
                fund_payment_receipt: receiptUrl,
                insert_date: formatDateToDDMMYYYY(item.insert_date)
            };
        });

        if (formattedResults.length > 0) {
            res.json({
                success: true,
                fund_req_history: formattedResults,
                msg: 'Fund Request History Data',
            });
        } else {
            res.json({
                success: false,
                fund_req_history: [],
                msg: 'Data Not Available',
            });
        }
    } catch (err) {
        console.error('Error in apiFundRequestHistory:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiCheckUserForTransferAmt = async (req, res) => {
    try {
        let { mobile } = req?.body || null;
        const userData = req?.user || null;

        mobile = Number(toStr(mobile));

        if (!mobile) {
            return res.status(404).json({
                success: false,
                msg: 'Mobile number is required',
            });
        }

        if (!userData) {
            return res.status(401).json({
                success: false,
                msg: 'User not found',
            });
        }

        if (userData.mobile === mobile) {
            return res.json({
                success: true,
                user_name: userData.user_name,
                msg: 'Account found',
            });
        } else {
            return res.status(404).json({
                success: false,
                user_name: '',
                msg: 'Account not found',
            });
        }
    } catch (err) {
        console.error('Error in apiCheckUserForTransferAmt:', err.message || err);
        return res.status(500).json({
            success: false,
            msg: 'Internal Server Error',
        });
    }
};

const apiUserTransferWalletBalance = async (req, res) => {
    try {
        let { mobile = "", amount = "", transfer_note = "" } = req?.body || {};
        const sender = req?.user || null;

        mobile = Number(toStr(mobile));
        amount = Number(toStr(amount));
        transfer_note = toStr(transfer_note);

        if (!sender) {
            return res.status(401).json({ success: false, msg: 'Unauthorized access' });
        }

        if (!transfer_note) {
            return res.status(404).json({ success: false, msg: 'Transfer note is required' });
        }

        if (!mobile || !amount || isNaN(amount) || amount <= 0) {
            return res.status(400).json({ success: false, msg: 'Invalid input. Ensure amount is a positive number' });
        }

        if (sender.mobile === mobile) {
            return res.status(400).json({ success: false, msg: 'You cannot transfer to yourself' });
        }

        if (sender.wallet_balance < amount) {
            return res.status(400).json({
                success: false,
                msg: 'Insufficient balance. Your transfer amount exceeds your wallet balance.',
            });
        }

        sender.wallet_balance -= amount;
        await sender.save();

        const receiver = await user_module.findOne({ mobile });
        if (!receiver) {
            return res.status(404).json({ success: false, msg: 'Receiver not found' });
        }

        receiver.wallet_balance += amount;
        await receiver.save();

        const txRequestNumber = getUserRandomToken(7, true);

        await wallet_trans_history_module.create({
            userDB_id: sender._id,
            amount,
            transaction_type: 2,
            transaction_note: `Amount Transfer To ${receiver.user_name}`,
            transfer_note,
            amount_status: 3,
            tx_request_number: txRequestNumber,
        });

        await wallet_trans_history_module.create({
            userDB_id: receiver._id,
            amount,
            transaction_type: 1,
            transaction_note: `Amount Received From ${sender.user_name}`,
            transfer_note,
            amount_status: 4,
            tx_request_number: txRequestNumber,
        });

        return res.json({ success: true, msg: 'Amount successfully transferred' });
    } catch (err) {
        console.error('Error in apiUserTransferWalletBalance:', err.message || err);
        return res.status(500).json({ success: false, success: false, msg: 'Internal Server Error' });
    }
};

const apiUserPaymentMethodList = async (req, res) => {
    try {
        const userData = req?.user || null;
        if (!userData || !userData._id) {
            return res.status(401).json({ success: false, msg: 'User not found' });
        }

        const paymentMethods = await user_bank_details_module.findOne({ userDB_id: userData._id }).lean();

        if (paymentMethods) {
            const paymentMethodArray = [];

            if (paymentMethods.ac_number) {
                paymentMethodArray.push({ type: 1, value: paymentMethods.ac_number, name: "Account number" });
            }
            if (paymentMethods.paytm_number) {
                paymentMethodArray.push({ type: 2, value: paymentMethods.paytm_number, name: "PayTM" });
            }
            if (paymentMethods.google_pay_number) {
                paymentMethodArray.push({ type: 3, value: paymentMethods.google_pay_number, name: "Google Pay" });
            }
            if (paymentMethods.phone_pay_number) {
                paymentMethodArray.push({ type: 4, value: paymentMethods.phone_pay_number, name: "Phone Pay" });
            }

            const minWithdrawal = await fix_values_module.findOne().lean();
            if (!minWithdrawal) {
                return res.status(400).json({ success: false, msg: 'minWithdraw settings not found' });
            }
            return res.json({
                success: true,
                result: paymentMethodArray,
                min_amt: minWithdrawal ? minWithdrawal.min_withdrawal : 0,
                msg: 'User Payment Method List',
            });
        } else {
            const maxWithdrawal = await fix_values_module.findOne().lean();
            ;
            if (!maxWithdrawal) {
                return res.status(400).json({ success: false, msg: 'maxWithdraw not found' });
            }
            return res.status(404).json({
                success: false,
                result: [],
                min_amt: maxWithdrawal ? maxWithdrawal.max_withdrawal : 0,
                msg: 'User Payment Method Not Added Yet',
            });
        }
    } catch (err) {
        console.error('Error in apiUserPaymentMethodList:', err.message || err);
        return res.status(500).json({
            success: false,
            msg: 'Internal Server Error',
        });
    }
};


const apiHowToPlay = async (req, res) => {

    try {
        const result = await how_to_play_module.findOne().lean();

        if (result) {
            return res.json({
                success: true,
                content: result,
                msg: 'Content Available.',
            });
        } else {
            return res.status(404).json({
                success: false,
                content: [],
                msg: 'Content Not Available.',
            });
        }
    } catch (error) {
        console.error('Error in apiHowToPlay:', error);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiViewWalletTransactionHistory = async (req, res) => {
    try {
        const baseUrl = process?.env?.BASE_URL;
        if (!baseUrl) {
            return res.status(500).json({ success: false, msg: "Base URL not set" });
        }
        let { transactionDB_id } = req?.body || {};
        transactionDB_id = toStr(transactionDB_id);
        const userData = req?.user || null;
        if (!userData || !userData._id) {
            return res.status(401).json({ success: false, msg: 'User not found' });
        }

        if (!transactionDB_id) {
            return res.status(400).json({ success: false, msg: 'Transaction ID is required' });
        }

        const transaction = await wallet_trans_history_module.findOne({
            userDB_id: userData._id,
            _id: transactionDB_id
        }).lean();
        if (!transaction) {
            return res.status(404).json({ success: false, msg: 'Transaction not found. Please check the details.' });
        }

        const amount_status = transaction.amount_status;
        let transaction_Data = [];

        if (amount_status === 1) {
            const fundRequest = await add_fund_request_module.findOne({ request_number: transaction.tx_request_number }).lean();
            if (fundRequest) {
                let receiptUrl = '';
                if (fundRequest.fund_payment_receipt) {
                    receiptUrl = `${baseUrl}/file/uploads/images/${item?.fund_payment_receipt?.toString()}`;
                }
                transaction_Data.push({
                    amount: transaction.amount,
                    transaction_type: transaction.transaction_type,
                    transaction_note: transaction.transaction_note,
                    transfer_note: transaction.transfer_note,
                    tx_request_number: transaction.tx_request_number,
                    amount_status,
                    fund_payment_receipt: receiptUrl,
                    insert_date: formatDateToDDMMYYYY(transaction.insert_date) + "," + get12HoursTimeFromISO(transaction.insert_date)
                });
            }

        } else if (amount_status === 2) {
            const paymentRequest = await withdraw_fund_request_module.findOne({ request_number: transaction.tx_request_number }).lean();
            const fundRequest = await add_fund_request_module.findOne({ request_number: transaction.tx_request_number }).lean();

            if (paymentRequest && fundRequest) {
                let receiptUrl = '';
                if (fundRequest.fund_payment_receipt) {
                    receiptUrl = `${baseUrl}/file/uploads/images/${fundRequest?.fund_payment_receipt?.toString()}`;
                }
                transaction_Data.push({
                    amount: transaction.amount,
                    transaction_type: transaction.transaction_type,
                    transaction_note: transaction.transaction_note,
                    transfer_note: transaction.transfer_note,
                    tx_request_number: transaction.tx_request_number,
                    amount_status,
                    payment_receipt: receiptUrl,
                    insert_date: formatDateToDDMMYYYY(transaction.insert_date) + "," + get12HoursTimeFromISO(transaction.insert_date),
                    payment_method: paymentRequest.payment_method,
                    bank_name: paymentRequest.bank_name,
                    branch_address: paymentRequest.branch_address,
                    ac_holder_name: paymentRequest.ac_holder_name,
                    ac_number: paymentRequest.ac_number,
                    ifsc_code: paymentRequest.ifsc_code,
                    paytm_number: paymentRequest.paytm_number,
                    google_pay_number: paymentRequest.google_pay_number,
                    phone_pay_number: paymentRequest.phone_pay_number,
                    remark: paymentRequest.remark
                });
            } else {
                return res.status(404).json({
                    success: false,
                    msg: 'Payment or Fund Request not found. Please check the details.'
                });
            }
        } else if ([3, 4, 6, 8].includes(amount_status)) {
            transaction_Data.push({
                amount: transaction.amount,
                transaction_type: transaction.transaction_type,
                transaction_note: transaction.transaction_note,
                transfer_note: transaction.transfer_note,
                amount_status,
                insert_date: formatDateToDDMMYYYY(transaction.insert_date) + "," + get12HoursTimeFromISO(transaction.insert_date),
                tx_request_number: transaction.tx_request_number
            });
        } else if (amount_status === 5) {
            const bidTx = await bid_history_module.findOne({ bid_tx_id: transaction.tx_request_number }).lean();
            if (bidTx) {
                transaction_Data.push({
                    amount: transaction.amount,
                    transaction_type: transaction.transaction_type,
                    transaction_note: transaction.transaction_note,
                    transfer_note: transaction.transfer_note,
                    tx_request_number: transaction.tx_request_number,
                    amount_status,
                    insert_date: formatDateToDDMMYYYY(transaction.insert_date) + "," + get12HoursTimeFromISO(transaction.insert_date),
                    game_name: bidTx.game_name,
                    pana: bidTx.pana,
                    session: bidTx.session,
                    digits: bidTx.digits,
                    closedigits: bidTx.closedigits,
                    bid_date: bidTx.bid_date
                });
            } else {
                return res.status(404).json({
                    success: false,
                    msg: 'Bid transaction not found. Please check the transaction ID.'
                });
            }
        }

        if (transaction_Data.length > 0) {
            return res.json({
                success: true,
                transaction_Data,
                msg: 'Wallet Transaction Data',
            });
        } else {
            return res.json({
                success: false,
                transaction_Data,
                msg: 'Transaction Data Not Available',
            });
        }
    } catch (err) {
        console.error('Error in apiViewWalletTransactionHistory:', err);
        res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiUserWithdrawTransactionHistory = async (req, res) => {
    try {
        const baseUrl = process?.env?.BASE_URL;
        if (!baseUrl) {
            return res.status(500).json({ success: false, msg: "Base URL not set" });
        }
        const userData = req?.user || null;
        if (!userData || !userData._id) {
            return res.status(401).json({ success: false, msg: 'Unauthorized request' });
        }

        const withdrawData = await withdraw_fund_request_module
            .find({ userDB_id: userData._id })
            .sort({ insert_date: -1 })
            .lean();

        const formattedWithdrawData = withdrawData && withdrawData.map(entry => {
            const { payment_receipt, insert_date, ...rest } = entry;

            let receiptUrl = '';
            if (payment_receipt) {
                receiptUrl = `${baseUrl}/file/uploads/images/${payment_receipt?.toString()}`;
            }

            return {
                ...rest,
                amount: `${entry.amount}`,
                fund_status: `${entry.fund_status}`,
                ac_number: `${entry.ac_number}`,
                withdraw_type: `${entry.withdraw_type}`,
                payment_method: `${entry.payment_method}`,
                payment_receipt: receiptUrl,
                insert_date: formatDateToDDMMYYYY(insert_date) + "," + get12HoursTimeFromISO(insert_date)
            };
        });

        const latestRequest = await withdraw_fund_request_module.findOne({ userDB_id: userData._id })
            .sort({ insert_date: -1 })
            .lean()

        const last_request_status = latestRequest ? latestRequest.request_status : '';

        const settings = await fix_values_module.findOne();
        let withdraw_open_time = '';
        let withdraw_close_time = '';
        if (settings) {
            withdraw_open_time = get12HoursTimeFromISO(settings.withdraw_open_time)
            withdraw_close_time = get12HoursTimeFromISO(settings.withdraw_close_time)
        } else {
            return res.status(500).json({ success: false, msg: 'Withdraw timings not set in settings' });
        }

        const walletInfo = await user_module.findOne({ _id: userData._id })

        return res.json({
            success: formattedWithdrawData.length > 0,
            withdrawdata: formattedWithdrawData,
            last_request_status,
            withdraw_open_time,
            withdraw_close_time,
            wallet_amt: walletInfo?.wallet_balance || '',
            msg: formattedWithdrawData.length > 0 ? 'Withdraw Transaction Data' : 'Withdraw Transaction Data Not Available',
        });

    } catch (err) {
        console.error('Error in apiUserWithdrawTransactionHistory:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

// middleware not used for JWT token
const apiGetSocialData = async (req, res) => {
    try {
        let { app_key = "", env_type = "" } = req?.body || {};
        app_key = toStr(app_key);
        env_type = toStr(env_type);

        if (!app_key || !env_type) {
            return res.status(400).json({ success: false, msg: 'app_key and env_type are required' });
        }

        if (checkRequestAuth(app_key, env_type) !== 0) {
            const result = await contact_settings_module.findOne({}, { _id: 0 }).lean();
            if (!result) {
                return res.status(404).json({ success: false, msg: 'Contact settings not found' });
            }

            const response = {
                success: true,
                ...result,
                msg: 'Success',
            };
            return res.json(response);
        } else {
            return res.status(401).json({ success: false, msg: 'UnAuthorized request' });
        }
    } catch (err) {
        console.error('Error in apiGetSocialData:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiValidateBank = async (req, res) => {
    try {
        const userData = req?.user || null;
        if (!userData || !userData._id) {
            return res.status(401).json({ success: false, msg: 'User not found' });
        }

        const mobile = userData?.mobile;

        const otp = getOtp(mobile);

        if (otp !== 1234) {
            const message = otp.toString().replace(/\s+/g, '');
            // await sendMessage(mobile, message); // Uncomment and implement
        }

        return res.json({
            success: true,
            otp,
            msg: 'Success',
        });

    } catch (error) {
        console.error('Error in apiValidateBank:', error);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

// middleware not used for JWT token
const apiGetUpdateResult = async (req, res) => {
    try {
        let { app_key = "", env_type = "" } = req?.body || {};
        app_key = toStr(app_key);
        env_type = toStr(env_type);

        if (!app_key || !env_type) {
            return res.status(400).json({ success: false, msg: 'app_key and env_type are required' });
        }

        if (checkRequestAuth(app_key, env_type) === 0) {
            return res.status(401).json({ success: false, msg: 'UnAuthorized request' });
        }

        const now = new Date();
        const openTime = new Date(`${now.toISOString().split('T')[0]}T00:00:00`);
        const closeTime = new Date(`${now.toISOString().split('T')[0]}T08:00:00`);
        let date = '';

        if (openTime > closeTime) {
            date = now.toISOString().split('T')[0];
        } else {
            const previousDay = new Date(now);
            previousDay.setDate(now.getDate() - 1);
            date = previousDay.toISOString().split('T')[0];
        }

        const games = await games_module.find().lean();

        const marketData = [];

        for (const game of games) {
            const result = await game_result_history_module.findOne({
                gameDB_id: game._id,
                result_date: date
            }).lean();

            if (result) {
                const gameObj = game.toObject();
                const resultObj = result.toObject();

                const mergedData = {
                    ...gameObj,
                    ...resultObj
                };
                marketData.push(mergedData);
            }
        }

        for (let rs of marketData) {
            const { gameDB_id, game_name } = rs;
            const dayOfWeek = new Intl.DateTimeFormat('en-US', { weekday: 'long' }).format(now);

            const gameDayResult = await weekday_games_module.findOne({ gameDB_id, name: dayOfWeek }).lean();

            if (gameDayResult) {
                rs.open_time = gameDayResult.open_time;
                rs.open_time_sort = gameDayResult.open_time_sort;
                rs.close_time = gameDayResult.close_time;
                rs.market_status = gameDayResult.weekday_status;
            }

            if (rs.market_status !== 0) {
                if (gameDB_id && game_name) {
                    resultDeclare(rs.open_time, rs.close_time, gameDB_id, game_name);
                }
            }
        }

        marketData.sort((a, b) => {
            return a.open_time_sort.localeCompare(b.open_time_sort);
        });

        const desawarGame = await gali_disswar_games_module.find({ status: 1 }).lean();

        desawarGame.sort((a, b) => {
            return a.open_time_sort.localeCompare(b.open_time_sort);
        });

        for (let game of desawarGame) {
            const open_time = game.open_time;
            const open = new Date(`${now.toISOString().split('T')[0]}T${open_time}`);

            const timeDifference = open.getTime() + 15 * 60 * 1000;
            if (now >= new Date(timeDifference)) {
                declareDessawar(game);
            }
        }

        const dataJson = {
            success: true,
            msg: 'Success',
            result: [],
        };

        return res.json(dataJson);

    } catch (error) {
        console.error('Error in apiGetUpdateResult:', error);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiGetLotteryData = async (req, res) => {
    try {
        let { playerDB_id = "" } = req?.body || {};
        playerDB_id = toStr(playerDB_id);

        if (!playerDB_id) {
            return res.status(400).json({ success: false, msg: 'playerDB_id is required' });
        }

        const userData = req.user;
        if (!userData) {
            return res.status(401).json({ success: false, msg: 'User not found' });
        }

        if (!mongoose.isValidObjectId(playerDB_id)) {
            return res.status(400).json({ success: false, msg: "Invalid ID" });
        }

        const existingPlayer = await player_ids_module.findOne({ playerDB_id });
        const playerData = { userDB_id: userData._id, playerDB_id };
        if (!existingPlayer) {
            await player_ids_module.create(playerData);
        }

        await user_module.updateOne({ userDB_id: userData._id }, { last_update: new Date() });

        const now = new Date();
        const close = new Date();
        close.setHours(8, 0, 0, 0);
        const resultDate = now > close ? now.toISOString().split('T')[0] :
            new Date(now.getTime() - 86400000).toISOString().split('T')[0];

        const lotteries = await lottery_module.find({ status: 1 })

        lotteries.sort((a, b) => {
            return a.open_date_sort.localeCompare(b.open_date_sort);
        });

        const result = [];

        for (const lottery of lotteries) {
            const resultData = await lottery_result_history_module.findOne({
                lotteryDB_id: lottery._id,
                result_date: resultDate
            }).lean();

            const lotteryObj = lottery.toObject();

            if (resultData) {
                const resultObj = resultData.toObject();
                result.push({ ...lotteryObj, ...resultObj });
            } else {
                result.push(lotteryObj);
            }
        }

        const formattedResult = result.map(item => {
            const nowDate = new Date().toISOString().split('T')[0];
            const openDate = new Date(item.open_date).toISOString().split('T')[0];
            const closeDate = new Date(item.close_date).toISOString().split('T')[0];

            const gameStatus = nowDate < openDate || nowDate > closeDate ? 2 : 1;
            const msg = gameStatus === 2 ? 'Market closed' : 'Market Running';
            const msg_hindi = gameStatus === 2 ? 'à¤¬à¤¾à¤œà¤¾à¤° à¤¬à¤‚à¤¦' : 'à¤¬à¤¾à¤œà¤¾à¤° à¤–à¥à¤²à¤¾';

            const openDuration = new Date(item.open_date) - now;
            const closeDuration = new Date(item.close_date) - now;

            return {
                lottery_id: item.lottery_id,
                lottery_name: item.lottery_name,
                lottery_name_hindi: item.lottery_name_hindi,
                no_of_tickets: item.no_of_tickets,
                start_from: item.start_from,
                lottery_image: item.lottery_image,
                price: item.price,
                open_date: item.open_date,
                open_date_sort: item.open_date_sort,
                close_date: item.close_date,
                first_prize: item.first_prize,
                second_prize: item.second_prize,
                third_prize: item.third_prize,
                msg,
                msg_hindi,
                msg_status: gameStatus,
                lottery_result: item.ticket_decleare_status === 1 ? 'declared' : '',
                open_duration: Math.max(openDuration, 0),
                close_duration: Math.max(closeDuration, 0),
                time_srt: new Date(item.open_date_sort).getTime()
            };
        });

        const sortedResult = formattedResult.sort((a, b) => a.time_srt - b.time_srt);
        return res.json({
            status: true,
            web_lottery_chart_url: `${process.env.BASE_URL || ''}/lottery-result-chart-details`,
            result: sortedResult,
            msg: 'Success',
        });
    } catch (error) {
        console.error('apiGetLotteryData Error:', error);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

// middleware not used for JWT token
const apiCheckGamesActiveInactive = async (req, res) => {
    try {
        let { app_key = "", env_type = "", gameDB_id = "" } = req?.body || {};
        app_key = toStr(app_key);
        env_type = toStr(env_type);
        gameDB_id = toStr(gameDB_id);

        if (!app_key || !env_type || !gameDB_id) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        if (checkRequestAuth(app_key, env_type) === 0) {
            return res.status(401).json({
                success: false,
                msg: 'Unauthorized request',
            });
        }

        const result = await games_module.findById(gameDB_id).lean();
        if (!result) {
            return res.status(404).json({ success: false, msg: 'Game not found' });
        }

        const responseData = await Promise.all(result.map(async (rs) => {
            const statusData = checkGameStatus(rs.open_time, rs.close_time);
            return {
                ...rs.toObject(),
                msg: statusData.msg,
                msg_hindi: statusData.msg_hindi,
                game_status: statusData.game_status,
                status: statusData.status
            };
        }));

        return res.json({ success: true, result: responseData });
    } catch (error) {
        console.error('apiCheckGamesActiveInactive Error:', error);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiLotteryBid = async (req, res) => {
    try {
        let {
            language = 'en',
            lotteryDB_id = "",
            lottery_name = "",
            rawTicketNum = "",
            totalbit = ""
        } = req?.body || {};

        lotteryDB_id = toStr(lotteryDB_id);
        lottery_name = toStr(lottery_name);
        rawTicketNum = Number(toStr(rawTicketNum));
        totalbit = Number(toStr(totalbit));

        if (!lotteryDB_id || !lottery_name || !rawTicketNum || !totalbit) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        const userData = req.userData;
        if (!userData) {
            return res.status(404).json({ success: false, msg: 'User not found' });
        }

        const lottery = await lottery_module.findById(lotteryDB_id).lean();
        if (!lottery) {
            return res.status(404).json({ success: false, msg: 'No Lottery Found' });
        }

        const { start_from, no_of_tickets, open_date, close_date } = lottery;

        if (rawTicketNum < start_from || rawTicketNum >= start_from + no_of_tickets) {
            return res.json({ success: false, msg: 'Wrong Ticket Number Selected', game_status: 2 });
        }

        const ticket = await lottery_tickets_module.findOne({
            lotteryDB_id,
            ticket_number: rawTicketNum,
            status: 'available'
        });
        if (!ticket) {
            return res.json({ success: false, msg: 'Ticket Number is not available', game_status: 2 });
        }

        const today = new Date().toISOString().slice(0, 10);
        const openTs = new Date(open_date).toISOString().slice(0, 10);
        const closeTs = new Date(close_date).toISOString().slice(0, 10);
        if (today < openTs || today > closeTs) {
            return res.json({ success: false, msg: 'Sorry Lottery Purchase Time Is Closed', game_status: 2 });
        }

        if (totalbit < 0) {
            return res.status(400).json({ success: false, msg: 'Sorry, something went wrong. Invalid totalbit value.' });
        }

        if (userData.wallet_balance < totalbit) {
            return res.json({ success: false, msg: "Sorry You Don't Have Sufficient Amount For This Bid" });
        }

        if (!mongoose.isValidObjectId(lotteryDB_id)) {
            return res.status(400).json({ success: false, msg: "Invalid ID" });
        }

        const bidTxId = getUserRandomToken(8, true);

        const bidDoc = new lottery_bid_history_module({
            userDB_id: userData._id,
            lotteryDB_id,
            lottery_name,
            rawTicketNum,
            points: totalbit,
            bid_date: today,
            bid_tx_id: bidTxId,
            insert_date: new Date()
        });
        await bidDoc.save();

        ticket.status = 'unavailable';
        await ticket.save();

        userData.wallet_balance = userData.wallet_balance - totalbit;
        await userData.save();

        const note = language === 'hi'
            ? `${lottery_name}(${rawTicketNum}) à¤²à¥‰à¤Ÿà¤°à¥€ à¤Ÿà¤¿à¤•à¤Ÿ à¤–à¤°à¥€à¤¦à¤¾`
            : `Bought ${lottery_name}(${rawTicketNum}) lottery ticket`;
        const history = new wallet_trans_history_module({
            userDB_id: userData._id,
            amount: totalbit,
            transaction_type: 2,
            transaction_note: note,
            amount_status: 5,
            tx_request_number: bidTxId,
            insert_date: new Date()
        });
        await history.save();

        return res.json({ success: true, msg: 'Buy Ticket Successfully.' });
    } catch (err) {
        console.error('apiLotteryBid error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiLotteryPayment = async (req, res) => {
    try {
        let {
            language = 'en',
            lotteryDB_id = "",
            lottery_name = "",
            ticket_num = "",
            totalbit = "",
            txn_id = "",
            txn_ref = "",
            payby = ""
        } = req?.body || {};

        lotteryDB_id = toStr(lotteryDB_id);
        lottery_name = toStr(lottery_name);
        ticket_num = Number(toStr(ticket_num));
        totalbit = Number(toStr(totalbit));
        texn_if = Number(toStr(txn_id));
        txn_ref = Number(toStr(txn_ref));
        payby = toStr(payby);

        if (!lotteryDB_id || !lottery_name || !ticket_num || !totalbit || !texn_if || !txn_ref || !payby) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        const userData = req.user
        if (!userData) {
            return res.status(404).json({ success: false, msg: 'User not found' });
        }

        const lottery = await lottery_module.findById(lotteryDB_id).lean();
        if (!lottery) {
            return res.status(404).json({ success: false, msg: 'No Lottery Found' });
        }

        if (!mongoose.isValidObjectId(lotteryDB_id)) {
            return res.status(400).json({ success: false, msg: "Invalid ID" });
        }

        const ticketNumber = parseInt(ticket_num);
        if (
            ticketNumber < lottery.start_from ||
            ticketNumber >= lottery.start_from + lottery.no_of_tickets
        ) {
            return res.json({ success: false, msg: 'Wrong Ticket Number Selected', game_status: 2 });
        }

        const ticketAvailable = await lottery_tickets_module.findOne({
            ticket_number: ticketNumber,
            status: 'available'
        }).lean();

        if (!ticketAvailable) {
            return res.status(404).json({ success: false, msg: 'Ticket Number is not available', game_status: 2 });
        }

        const today = new Date().toISOString().slice(0, 10);
        const openDate = new Date(lottery.open_date);
        const closeDate = new Date(lottery.close_date);

        if (new Date(today) < openDate || new Date(today) > closeDate) {
            return res.json({
                success: false,
                msg: 'Sorry Lottery Purchase Time Is Closed',
                game_status: 2,
            });
        }

        if (totalbit < 0) {
            return res.status(400).json({ success: false, msg: 'Sorry, something went wrong. Invalid totalbit value.' });
        }

        const request_number = getUserRandomToken(20, true);

        const bid = new lottery_bid_history_module({
            userDB_id: userData._id,
            lotteryDB_id,
            lottery_name,
            ticket_num: ticketNumber,
            points: totalbit,
            bid_date: today,
            bid_tx_id: texn_if,
            insert_date: new Date()
        });
        await bid.save();

        await lottery_tickets_module.updateOne(
            { _id: ticketAvailable._id },
            { $set: { status: 'unavailable' } }
        );

        const transaction_note =
            language === 'hi'
                ? `${lottery_name}(${ticketNumber}) à¤²à¥‰à¤Ÿà¤°à¥€ à¤Ÿà¤¿à¤•à¤Ÿ à¤–à¤°à¥€à¤¦à¤¾`
                : `Bought ${lottery_name}(${ticketNumber}) lottery ticket`;

        const history = new wallet_trans_history_module({
            userDB_id: userData._id,
            amount: totalbit,
            transaction_type: 2,
            transaction_note,
            amount_status: 5,
            tx_request_number: request_number,
            txn_id: texn_if,
            txn_ref,
            payby
        });
        await history.save();

        return res.json({ success: true, msg: 'Buy Ticket Successfully.' });
    } catch (err) {
        console.error(err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

// middleware not used for JWT token
const apiSubmitContactUs = async (req, res) => {
    try {
        let { app_key = '', env_type = '', user_name = "", mobile = "", username = "", enquiry = "" } = req?.body || {};
        app_key = toStr(app_key);
        env_type = toStr(env_type);
        user_name = toStr(user_name);
        mobile = Number(toStr(mobile));
        username = toStr(username);
        enquiry = toStr(enquiry);
        if (!app_key || !env_type || !user_name || !mobile || !username || !enquiry) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        let mobileRegex = /^[0-9]{10}$/;
        if (!mobileRegex.test(mobile)) {
            return res.status(400).json({ success: false, msg: 'Invalid mobile number. Must be exactly 10 digits.' });
        }

        if (checkRequestAuth(app_key, env_type) === 0) {
            return res.status(401).json({ success: false, msg: 'UnAuthorized request' });
        }

        const contact = new contact_settings_module({
            user_name: (user_name || '').toString().split(' ').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' '),
            mobile,
            username,
            enquiry,
            insert_date: new Date()
        });
        await contact.save();

        return res.json({ success: true, msg: 'Successfully Submitted. Please Wait For The Response' });
    } catch (err) {
        console.error('apiSubmitContactUs error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiWinningHistoryData = async (req, res) => {
    try {
        let {
            // date_from = '',
            // date_to = ''
            session,
            gameListId,
            page = 1,
            limit = 10
        } = req?.body || {};

        // console.log("🚀 ~ apiWinningHistoryData ~ req?.body:", req?.body)

        const skip = (page - 1) * limit;

        // date_from = toStr(date_from);
        // date_to = toStr(date_to);
        console.log("session", session)
        console.log("gameListId", gameListId)

        if (!gameListId) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        const userData = req?.user || null;
        // console.log("🚀 ~ apiWinningHistoryData ~ userData:", userData)

        // console.log(`(((((((()))))) ~ mobileController.js:5607 ~ apiWinningHistoryData ~ userData:`, userData);
        if (!userData) {
            return res.status(404).json({ success: false, msg: 'User not found' });
        }


        // Build matchStage (assuming it's initialized earlier, e.g., 
        const matchStage = { amount_status: 8 };
        matchStage.userDB_id = userData._id;
        // matchStage.insert_date = { $gte: start, $lte: end }; // Add date filter here for consistency


        if (gameListId.length > 0) {
            // console.log(" apiWinningHistoryData ~ gameListId:", gameListId)
            const objectIdArray = gameListId.map(id => new mongoose.Types.ObjectId(id));
            matchStage.main_gameDB_id = { $in: objectIdArray };
        }
        else {
            const main_game_ids = await games_module.find({}, { _id: 1 });
            // console.log(" main_game_ids ~ main_game_ids:", main_game_ids); // Fixed log name

            if (main_game_ids.length > 0) {
                // Extract just the _id values for $in
                const gameIds = main_game_ids.map(game => game._id);
                matchStage.main_gameDB_id = { $in: gameIds }; // Use consistent field name
            }

        }


        // console.log("🚀 ~ apiStarlineWiningHistoryData ~ matchStage:", matchStage);
        const totalWinResultCount = await wallet_trans_history_module.countDocuments(matchStage);
        // console.log(`(((((((()))))) ~ mobileController.js:5627 ~ apiWinningHistoryData ~ totalWinResultCount:`, totalWinResultCount);

        const transactions = await wallet_trans_history_module
            .find(matchStage) // Now uses the built matchStage
            .sort({ insert_date: -1 })
            .skip(skip)
            .limit(limit)
            .lean();

        console.log(`(((((((()))))) ~ mobileController.js:5632 ~ apiWinningHistoryData ~ transactions:`, transactions);

        const results = [];


        for (const tx of transactions) {

            let sessionfilter = { bid_tx_id: tx.bid_tx_id, };
            if (session === 'Open') { sessionfilter.session = "Open" }
            if (session === 'Close') { sessionfilter.session = "Close" }


            console.log("🚀 ~ apiWinningHistoryData ~ tx:", tx.tx_request_number)
            const bidInfo = await bid_history_module.findOne(sessionfilter);
            console.log("🚀 ~ apiWinningHistoryData ~ bidInfo:", bidInfo)

            if (bidInfo) {
                results.push({
                    amount: `${tx.amount}`,
                    transaction_type: `${tx.transaction_type}`,
                    transaction_note: tx.transaction_note,
                    amount_status: `${tx.amount_status}`,
                    tx_request_number: tx.tx_request_number,
                    wining_date: tx.insert_date.toLocaleString('en-IN', {
                        day: '2-digit',
                        month: 'short',
                        year: 'numeric',
                        hour: '2-digit',
                        minute: '2-digit',
                        second: '2-digit',
                        hour12: true
                    }),
                    game_name: bidInfo.game_name,
                    pana: bidInfo.pana,
                    session: bidInfo.session,
                    digits: bidInfo.digits,
                    closedigits: bidInfo.closedigits
                });
            }
        }

        if (results.length > 0) {
            return res.json({ success: true, win_data: results, msg: 'Wining History Data Available', total_count: totalWinResultCount });
        } else {
            return res.json({ success: false, win_data: [], msg: 'Wining History Data Not Available' });
        }
    } catch (error) {
        console.error('apiWinningHistoryData error:', error);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiGetTipsList = async (req, res) => {
    try {
        let tipsList = await tips_module.find({ status: 1 })

        if (tipsList.length > 0) {
            const formatted = tipsList.map(tip => ({
                tipsDB_id: tip._id,
                title: tip.title,
                banner_image: `base:${tip.banner_image.content_type};base64,${tip.banner_image.fileBuffer.toString('base64')}`,
                insert_date: new Date(tip.insert_date).toLocaleDateString('en-US', {
                    day: '2-digit', month: 'short', year: 'numeric'
                })
            }));
            return res.json({ success: true, tips: formatted, msg: 'Notice Data.' });
        } else {
            return res.json({ success: false, msg: 'Data Not Found.' });
        }
    } catch (err) {
        console.error('apiGetTipsList error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

// middleware not used for JWT token
const apiViewTipsDetails = async (req, res) => {
    try {
        let { app_key = '', env_type = '', tipsDB_id = "" } = req?.body || {};

        app_key = toStr(app_key);
        env_type = toStr(env_type);
        tipsDB_id = toStr(tipsDB_id);
        if (!app_key || !env_type || !tipsDB_id) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        const isAuthorized = await checkRequestAuth(app_key, env_type);
        if (!isAuthorized) {
            return res.json({
                success: false,
                msg: 'UnAuthorized request'
            });
        }

        const result = await tips_module.findOne({ _id: tipsDB_id, status: 1 });

        if (result) {
            const tipsDetails = {
                title: result.title,
                banner_image: `base:${tip.banner_image.content_type};base64,${tip.banner_image.fileBuffer.toString('base64')}`,
                description: result.description,
                insert_date: new Date(result.insert_date).toLocaleDateString('en-GB', {
                    day: '2-digit',
                    month: 'short',
                    year: 'numeric'
                })
            };

            res.json({
                success: true,
                tipsDetails,
                msg: 'Tips Data.',
            });
        } else {
            res.json({
                success: false,
                msg: 'Data Not Found.',
            });
        }

        if (result.length > 0) {
            return res.json({
                success: true,
                tipsDetails: result,
                msg: 'Tips Data.',
            });
        } else {
            return res.json({
                success: false,
                msg: 'Data Not Found.',
            });
        }
    } catch (err) {
        console.error('Error in apiViewTipsDetails:', err);
        return res.status(500).json({
            success: false,
            msg: 'Internal Server Error',
        });
    }
};



const apiCheckGameStatus = async (req, res) => {
    try {
        let { gameDB_id = "" } = req?.body || {};
        gameDB_id = toStr(gameDB_id);
        if (!gameDB_id) {
            return res.status(400).json({ success: false, msg: "All fields are required." });
        }

        const userData = req?.user || null;
        if (!userData) {
            return res.status(404).json({ success: false, msg: "User not found" });
        }

        if (!mongoose.isValidObjectId(gameDB_id)) {
            return res.status(400).json({ success: false, msg: "Invalid ID" });
        }

        const todayName = new Date().toLocaleDateString("en-US", { weekday: "long" });
        const result = await weekday_games_module.findOne({
            gameDB_id,
            week_name: todayName.toLowerCase(),
        });

        let data_json = {};

        if (result) {
            if (result.weekday_status === 0) {
                data_json.msg = "Sorry Betting Is closed.";
                data_json.msg_hindi = "क्षमा करें बेटिंग बंद है";
                data_json.game_status = 2;
                data_json.status = false;
            } else {
                // 🕒 Current IST time
                const nowIST = moment_timeZone().tz("Asia/Kolkata");

                // 🕒 Convert DB UTC times to IST
                const openIST = moment_timeZone(result.open_time).tz("Asia/Kolkata");
                const closeIST = moment_timeZone(result.close_time).tz("Asia/Kolkata");

                // 🧮 Extract only time components (ignore date)
                const nowMinutes = nowIST.hours() * 60 + nowIST.minutes();
                const openMinutes = openIST.hours() * 60 + openIST.minutes();
                const closeMinutes = closeIST.hours() * 60 + closeIST.minutes();

                console.log("🕒 Now IST:", nowIST.format("HH:mm"));
                console.log("🕒 Open IST:", openIST.format("HH:mm"));
                console.log("🕒 Close IST:", closeIST.format("HH:mm"));

                // ✅ Compare only by time
                if (nowMinutes < openMinutes) {
                    data_json.msg = "Betting Is Open (for Open Session)";
                    data_json.msg_hindi = "बेटिंग ओपन सत्र के लिए खुली है";
                    data_json.session = "open";
                    data_json.game_status = 1;
                    data_json.status = true;
                } else {
                    data_json.msg = "Sorry Betting Is closed.";
                    data_json.msg_hindi = "क्षमा करें बेटिंग बंद है";
                    data_json.game_status = 2;
                    data_json.status = false;
                }
            }

            const device_result = await user_device_record_module
                .find({ userDB_id: userData._id })
                .sort({ id: -1 })
                .limit(Number(process.env.DEVICE_LIMIT || 5));

            data_json.device_result = device_result;
        } else {
            data_json.msg = "No game data for today";
            data_json.success = false;
        }

        res.json(data_json);
    } catch (err) {
        console.error(err);
        res.json({ success: false, msg: "Something went wrong" });
    }
};


const apiNotificationSetting = async (req, res) => {
    try {
        let { notification_status = "" } = req?.body || {};

        notification_status = toStr(notification_status)

        if (!notification_status) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        userData = req?.user || null
        if (!userData) {
            return res.status(404).json({ success: false, msg: "User not found" })
        }

        userData.notification_status = notification_status
        await userData.save()

        res.json({
            success: true,
            msg: 'Notification setting successfully updated',
        });
    } catch (error) {
        console.error('Update Error:', error);
        res.json({
            success: false,
            msg: 'Something went wrong',
        });
    }
};

const apiGetStatement = async (req, res) => {
    try {
        let { date_from = "", date_to = "" } = req?.body || {};

        date_from = toStr(date_from)
        date_to = toStr(date_to)

        if (!date_from || !date_to) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        userData = req?.user || null
        if (!userData) {
            return res.status(404).json({ success: false, msg: "User not found" })
        }

        const startDate = new Date(date_from);
        const endDate = new Date(date_to);
        endDate.setHours(23, 59, 59, 999); // ensure full day range

        const result = await wallet_trans_history_module.find({
            userDB_id: userData._id,
            insert_date: { $gte: startDate, $lte: endDate }
        })

        if (result.length > 0) {
            const formattedResult = result.map(item => ({
                ...item._doc,
                insert_date: new Date(item.insert_date).toLocaleString('en-GB', {
                    day: '2-digit', month: 'short', year: 'numeric',
                    hour: '2-digit', minute: '2-digit', second: '2-digit',
                    hour12: true
                })
            }));

            res.json({
                success: true,
                transaction_history: formattedResult,
                msg: 'Wallet Transaction History',
            });
        } else {
            res.json({
                success: false,
                transaction_history: [],
                msg: 'Wallet Transaction History Data Not Available',
            });
        }
    } catch (err) {
        console.error(err);
        res.json({ success: false, msg: 'Something went wrong' });
    }
};

const checkNotification = async () => {
    const to = '6f74087b-3eb2-4841-b218-51d2c111cc7e';
    const title = 'Demo';
    const message = 'Demo Data';
    const img = '';
    const type_id = '';

    try {
        // await sendNotification(to, title, message, img, type_id);
        console.log('Notification sent successfully');
        return {
            success: true,
            msg: 'Notification sent successfully',
            data: sendResult
        };
    } catch (err) {
        console.error('Failed to send notification:', err);
        return {
            success: false,
            msg: 'Failed to send notification',
            error: err.message || err
        };
    }
};

// middleware not used for JWT token
const apiGetAppVersionDetails = async (req, res) => {
    try {
        let { app_key = '', env_type = '' } = req?.body || {};

        app_key = toStr(app_key);
        env_type = toStr(env_type);

        if (!app_key || !env_type) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res.status(401).json({ success: false, msg: 'UnAuthorized request' });
        }

        const versionDetails = await app_setting_module.findOne().lean();
        if (!versionDetails) {
            return res.json({ success: false, msg: 'No App Version Data Found' });
        }

        if (versionDetails) {
            return res.json({
                success: true,
                versionDetails,
                msg: 'App Version Data.',
            });
        } else {
            return res.json({
                success: false,
                msg: 'Data Not Found.',
            });
        }
    } catch (err) {
        console.error('apiGetAppVersionDetails error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

// middleware not used for JWT token
const apiCheckStarLineGameStatus = async (req, res) => {
    try {
        let { app_key = '', env_type = '', gameDB_id = "" } = req?.body || {};

        app_key = toStr(app_key);
        env_type = toStr(env_type);
        gameDB_id = toStr(gameDB_id);

        if (!app_key || !env_type || !gameDB_id) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res.json({ success: false, msg: 'UnAuthorized request' });
        }

        if (!mongoose.isValidObjectId(gameDB_id)) {
            return res.status(400).json({ success: false, msg: "Invalid ID" });
        }

        const game = await starline_games_module.findOne(
            { gameDB_id },
        )

        if (!game) {
            return res.json({ success: false, msg: 'Game not found' });
        }

        const parse12h = (time12) => {
            const [time, meridiem] = time12.split(' ');
            let [h, m] = time.split(':').map(Number);
            if (meridiem === 'PM' && h !== 12) h += 12;
            if (meridiem === 'AM' && h === 12) h = 0;
            const today = new Date().toISOString().slice(0, 10);
            const hh = h.toString().padStart(2, '0');
            const mm = m.toString().padStart(2, '0');
            return new Date(`${today}T${hh}:${mm}:00`);
        };

        const now = new Date();
        const openDt = parse12h(game.open_time);

        let msg, msg_hindi, game_status, success;
        if (now > openDt) {
            success = false;
            msg = 'Sorry Betting Is closed.';
            msg_hindi = 'à¤•à¥à¤·à¤®à¤¾ à¤•à¤°à¥‡à¤‚ à¤¬à¥‡à¤Ÿà¤¿à¤‚à¤— à¤¬à¤‚à¤¦ à¤¹à¥ˆ';
            game_status = 2;
        } else {
            success = true;
            msg = 'Betting Is Open';
            msg_hindi = 'à¤¬à¥‡à¤Ÿà¤¿à¤‚à¤— à¤–à¥à¤²à¥€ à¤¹à¥ˆ';
            game_status = 1;
        }

        return res.json({ success, msg, msg_hindi, game_status });
    } catch (err) {
        console.error('apiCheckStarLineGameStatus error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

// middleware not used for JWT token
const apiCheckStarLineGamesActiveInactive = async (req, res) => {
    try {
        let { app_key = '', env_type = '', gameDB_id = "" } = req?.body || {};

        app_key = toStr(app_key);
        env_type = toStr(env_type);
        gameDB_id = toStr(gameDB_id);

        if (!app_key || !env_type || !gameDB_id) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res.json({ success: false, msg: 'UnAuthorized request' });
        }

        if (!mongoose.isValidObjectId(gameDB_id)) {
            return res.status(400).json({ success: false, msg: "Invalid ID" });
        }

        const game = await starline_games_module.findOne(
            { gameDB_id },
        )

        if (!game) {
            return res.json({ success: false, msg: 'Game not found' });
        }

        const data = getMsgAccordingToOpenTime(game.open_time);

        return res.json({
            success: true,
            result: [{
                open_time: game.open_time,
                close_time: game.close_time,
                msg: data.msg,
                msg_hindi: data.msg_hindi,
                game_status: data.game_status,
                status: data.status
            }],
        });
    } catch (err) {
        console.error('apiCheckStarLineGamesActiveInactive error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiStarlineBidHistoryData = async (req, res) => {
    try {
        let {
            // bid_from = '',
            // bid_to = '',
            session = 'both',
            page = 1,
            limit = 10,
            gameListId = []
        } = req?.body || {};

        // console.log("🚀 ~ apiStarlineBidHistoryData ~ req?.body:", req?.body)

        const userData = req?.user || null;

        const skip = (page - 1) * limit;
        const payload = {
            // userDB_id: userData._id
        }

        if (session == 'Open') {
            payload.session = session
        }

        if (session == 'Close') {
            payload.session = session
        }


        if (gameListId && gameListId.length > 0) {
            payload.gameDB_id = { $in: gameListId }
        }


        if (!userData) {
            return res.json({ success: false, msg: 'User not found' });
        }

        // let start, end;
        // if (!bid_from && !bid_to) {
        //     const today = new Date();
        //     start = new Date(today.setHours(0, 0, 0, 0));
        //     end = new Date(today.setHours(23, 59, 59, 999));
        // } else {
        //     start = bid_from
        //         ? new Date(new Date(bid_from).setHours(0, 0, 0, 0))
        //         : new Date(0);
        //     end = bid_to
        //         ? new Date(new Date(bid_to).setHours(23, 59, 59, 999))
        //         : new Date();
        // }

        const totalBidCount = await starline_bid_history_module.countDocuments(payload);
        console.log(`(((((((()))))) ~ mobileController.js:7103 ~ apiStarlineBidHistoryData ~ totalBidCount:`, totalBidCount);



        const bids = await starline_bid_history_module.find(payload).sort({ insert_date: -1 }).skip(skip).limit(limit).lean();

        const formatted = bids.map(b => ({
            ...b,
            winning_points: `${b.winning_points}` || 0,
            points: `${b.points}` || 0,
            status: `${b.status}`,
            pay_status: `${b.pay_status}`,
            bid_date: new Date(b.insert_date).toLocaleString('en-US', {
                day: '2-digit',
                month: 'short',
                year: 'numeric',
                hour: 'numeric',
                minute: 'numeric',
                second: 'numeric',
                hour12: true
            })
        }));

        if (formatted.length > 0) {
            return res.json({
                success: true,
                bid_data: formatted,
                total_count: totalBidCount,
                msg: 'Bid History Data Available',
            });
        } else {
            return res.json({
                success: false,
                bid_data: [],
                total_count: totalBidCount,
                msg: 'Bid History Data Not Available',
            });
        }
    } catch (err) {
        console.error('apiStarline BidHistoryData error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiStarlineWiningHistoryData = async (req, res) => {
    try {
        let {
            // date_from = '',
            // date_to = '',
            page = 1,
            limit = 10
        } = req?.body || {};

        const skip = (page - 1) * limit;

        const userData = req?.user || null;
        if (!userData) {
            return res.json({ success: false, msg: 'User not found' });
        }

        // let start, end;
        // if (!date_from && !date_to) {
        //     const today = new Date();
        //     start = new Date(today.setHours(0, 0, 0, 0));
        //     end = new Date(today.setHours(23, 59, 59, 999));
        // } else {
        //     start = date_from
        //         ? new Date(new Date(date_from).setHours(0, 0, 0, 0))
        //         : new Date(0);
        //     end = date_to
        //         ? new Date(new Date(date_to).setHours(23, 59, 59, 999))
        //         : new Date();
        // }


        // Build matchStage (assuming it's initialized earlier, e.g., 
        const matchStage = { amount_status: 8 };
        matchStage.userDB_id = userData._id;
        // matchStage.insert_date = { $gte: start, $lte: end }; // Add date filter here for consistency

        const starline_game_ids = await starline_games_module.find({}, { _id: 1 });
        console.log("🚀 ~ apiStarlineWiningHistoryData ~ starline_game_ids:", starline_game_ids); // Fixed log name

        if (starline_game_ids.length > 0) {
            // Extract just the _id values for $in
            const gameIds = starline_game_ids.map(game => game._id);
            matchStage.starline_gameDB_id = { $in: gameIds }; // Use consistent field name
        }

        console.log("🚀 ~ apiStarlineWiningHistoryData ~ matchStage:", matchStage);

        const totalWinResultCount = await wallet_trans_history_module.countDocuments(matchStage);
        console.log(`(((((((()))))) ~ mobileController.js:6153 ~ apiStarlineWiningHistoryData ~ totalWinResultCount:`, totalWinResultCount);

        const transactions = await wallet_trans_history_module
            .find(matchStage) // Now uses the built matchStage
            .sort({ insert_date: -1 })
            .skip(skip)
            .limit(limit)
            .lean();

        console.log("🚀 ~ apiStarlineWiningHistoryData ~ transactions count:", transactions.length); // Useful for debugging



        // const transactions = await wallet_trans_history_module.find({
        //     userDB_id: userData._id,
        //     gameDB_id: { $in: starline_game_ids },
        //     amount_status: 8,
        //     insert_date: { $gte: start, $lte: end }
        // }).sort({ insert_date: -1 }).skip(skip).limit(limit).lean();

        // console.log("🚀 ~ apiStarlineWiningHistoryData ~ userData._id:", userData._id)
        // console.log("🚀 ~ apiStarlineWiningHistoryData ~ transactions:", transactions)

        // console.log(`(((((((()))))) ~ mobileController.js:6186 ~ apiStarlineWiningHistoryData ~ transactions:`, transactions);

        // const txNumbers = transactions.map(tx => tx.tx_request_number);
        const txNumbers = transactions.map(tx => tx.bid_tx_id);

        // console.log(`(((((((()))))) ~ mobileController.js:6190 ~ apiStarlineWiningHistoryData ~ txNumbers:`, txNumbers);

        const bidInfos = await starline_bid_history_module.find({
            bid_tx_id: { $in: txNumbers }
        }).lean();

        console.log(`(((((((()))))) ~ mobileController.js:6194 ~ apiStarlineWiningHistoryData ~ bidInfos:`, bidInfos);

        const bidInfoMap = new Map();
        for (const bid of bidInfos) {
            bidInfoMap.set(bid.bid_tx_id, bid);
        }

        const records = transactions
            .map(tx => {
                const bid = bidInfoMap.get(tx.bid_tx_id);
                console.log("🚀 ~ apiStarlineWiningHistoryData ~ bid:", bid)
                if (!bid) return null;

                const insertDate = new Date(tx.insert_date);
                const options = {
                    day: '2-digit',
                    month: 'long',
                    year: '2-digit',
                    hour: '2-digit',
                    minute: '2-digit',
                    hour12: false
                };

                const wining_date = insertDate.toLocaleString('en-GB', options).replace(',', '');

                return {
                    amount: `${tx.amount}`,
                    transaction_type: `${tx.transaction_type}`,
                    transaction_note: tx.transaction_note,
                    amount_status: `${tx.amount_status}`,
                    tx_request_number: tx.tx_request_number,
                    wining_date,
                    game_name: bid.game_name,
                    pana: bid.pana,
                    session: bid.session,
                    digits: bid.digits,
                    closedigits: bid.closedigits
                };
            })
            .filter(record => record !== null);


        if (records.length > 0) {
            return res.json({
                success: true,
                win_data: records,
                total_count: totalWinResultCount,
                msg: 'Wining History Data Available',
            });
        } else {
            return res.json({
                success: false,
                win_data: [],
                total_count: totalWinResultCount,
                msg: 'Wining History Data Not Available',
            });
        }
    } catch (err) {
        console.error('apiStarlineWiningHistoryData error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

// middleware not used for JWT token
const apiStarlineGameNames = async (req, res) => {
    try {
        let { app_key = '', env_type = '' } = req?.body || {};

        app_key = toStr(app_key);
        env_type = toStr(env_type);

        if (!app_key || !env_type) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res.json({ success: false, msg: 'UnAuthorized request' });
        }

        const games = await starline_games_module.find({ status: 1 })

        if (games.length > 0) {
            return res.json({
                success: true,
                StarLineGameNames: games,
                msg: 'Game name Data.',
            });
        } else {
            return res.json({
                success: false,
                msg: 'Game name not found or not active.',
            });
        }
    } catch (err) {
        console.error('apiStarlineGameNames error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

// middleware not used for JWT token
const apiStarlineResultHistoryData = async (req, res) => {
    try {
        let { app_key = '', env_type = '', bid_from = '' } = req?.body || {};

        app_key = toStr(app_key);
        env_type = toStr(env_type);
        bid_from = toStr(bid_from);

        if (!app_key || !env_type || !bid_from) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res.json({ success: false, msg: 'UnAuthorized request' });
        }

        const dateStr = bid_from
            ? new Date(bid_from).toISOString().slice(0, 10)
            : new Date().toISOString().slice(0, 10);

        const results = await starline_game_result_history_module.find({
            result_date: dateStr
        }).lean();

        const gameIds = results.map(r => r.gameDB_id);

        const games = await starline_games_module.find({
            gameDB_id: { $in: gameIds }
        }).lean();

        const gameMap = new Map();
        for (const game of games) {
            gameMap.set(game.gameDB_id, game);
        }

        const raw = results.map(result => {
            const game = gameMap.get(result.gameDB_id) || {};
            return {
                open_number: result.open_number,
                game_name: game.game_name || null,
                game_name_hindi: game.game_name_hindi || null
            };
        });

        const result = raw.map(r => {
            const val = r.open_number || '';
            if (val) {
                const sum = val
                    .split('')
                    .map(d => parseInt(d, 10))
                    .reduce((a, b) => a + b, 0);
                const last = sum < 10 ? sum : sum % 10;
                r.open_number = `${val}-${last}`;
            }
            return r;
        });

        if (result.length > 0) {
            return res.json({
                success: true,
                Result_data: result,
                msg: 'Result History Data Available',
            });
        } else {
            return res.json({
                success: false,
                Result_data: [],
                msg: 'Result History Data Not Available',
            });
        }
    } catch (err) {
        console.error('apiStarlineResultHistoryData error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

// middleware not used for JWT token
const apiCheckGaliDisswarGameStatus = async (req, res) => {
    try {
        let { app_key = '', env_type = '', gameDB_id = "" } = req?.body || {};

        app_key = toStr(app_key);
        env_type = toStr(env_type);
        gameDB_id = toStr(gameDB_id);

        if (!app_key || !env_type || !gameDB_id) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res.json({ success: false, msg: 'UnAuthorized request' });
        }

        if (!mongoose.isValidObjectId(gameDB_id)) {
            return res.status(400).json({ success: false, msg: "Invalid ID" });
        }

        const game = await gali_disswar_games_module.findOne(
            { gameDB_id },
        );

        if (!game) {
            return res.json({ success: false, msg: 'Game not found' });
        }

        const [timePart, meridiem] = game.open_time.split(' ');
        let [hours, minutes] = timePart.split(':').map(Number);
        if (meridiem === 'PM' && hours !== 12) hours += 12;
        if (meridiem === 'AM' && hours === 12) hours = 0;
        const todayStr = new Date().toISOString().slice(0, 10);
        const hh = String(hours).padStart(2, '0');
        const mm = String(minutes).padStart(2, '0');
        const openDt = new Date(`${todayStr}T${hh}:${mm}:00`);

        const now = new Date();
        let msg, msg_hindi, game_status, success;
        if (now > openDt) {
            msg = 'Sorry Betting Is closed.';
            msg_hindi = 'à¤•à¥à¤·à¤®à¤¾ à¤•à¤°à¥‡à¤‚ à¤¬à¥‡à¤Ÿà¤¿à¤‚à¤— à¤¬à¤‚à¤¦ à¤¹à¥ˆ';
            game_status = 2;
            success = false;
        } else {
            msg = 'Betting Is Open';
            msg_hindi = 'à¤¬à¥‡à¤Ÿà¤¿à¤‚à¤— à¤–à¥à¤²à¥€ à¤¹à¥ˆ';
            game_status = 1;
            success = true;
        }

        return res.json({ msg, msg_hindi, game_status, success });
    } catch (err) {
        console.error('apiCheckGaliDisswarGameStatus error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

// middleware not used for JWT token
const apiCheckGaliDisswarGamesActiveInactive = async (req, res) => {
    try {
        let { app_key = '', env_type = '', gameDB_id = "" } = req.body;

        app_key = toStr(app_key);
        env_type = toStr(env_type);
        gameDB_id = toStr(gameDB_id);

        if (!app_key || !env_type || !gameDB_id) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res.json({ success: false, msg: 'UnAuthorized request' });
        }

        if (!mongoose.isValidObjectId(gameDB_id)) {
            return res.status(400).json({ success: false, msg: "Invalid ID" });
        }

        const game = await gali_disswar_games_module
            .findOne({ gameDB_id }, 'open_time close_time')
            .lean();

        if (!game) {
            return res.json({ success: false, msg: 'Game not found' });
        }

        const { msg, msg_hindi, game_status } = checkGameOpenStatus(game.open_time);

        return res.json({
            result: [{
                open_time: game.open_time,
                close_time: game.close_time,
                msg,
                msg_hindi,
                game_status,
                success
            }]
        });
    } catch (err) {
        console.error('apiCheckGaliDisswarGamesActiveInactive error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiGaliDisswarBidHistoryData = async (req, res) => {
    try {
        let {
            // bid_from = "", 
            // bid_to = "", 
            page = 1,
            limit = 10,
            gameListId
        } = req?.body || {};
        // console.log("🚀 ~ apiGaliDisswarBidHistoryData ~ req?.body:", req?.body)

        const skip = (page - 1) * limit;

        // bid_from = toStr(bid_from);
        // bid_to = toStr(bid_to);

        const userData = req?.user || null;
        if (!userData) {
            return res.json({ success: false, msg: 'User not found' });
        }

        let query = {};

        // if (bid_from && bid_to) {
        //     const date_from = new Date(bid_from);
        //     const date_to = new Date(bid_to);
        //     date_to.setHours(23, 59, 59, 999);
        //     query.bid_date = { $gte: date_from, $lte: date_to };
        // } else {
        //     const today = new Date();
        //     const todayStart = new Date(today.setHours(0, 0, 0, 0));
        //     const todayEnd = new Date(today.setHours(23, 59, 59, 999));
        //     query.bid_date = { $gte: todayStart, $lte: todayEnd };
        // }
        // console.log("🚀 ~ apiGaliDisswarBidHistoryData ~ userData._id:", userData._id)

        const payload = {
            userDB_id: userData._id
        }

        if (gameListId && gameListId.length > 0) {
            payload.gameDB_id = { $in: gameListId }
        }



        const totalCount = await gali_disswar_bid_history_module.countDocuments(
            payload
        );
        // console.log(`(((((((()))))) ~ mobileController.js:7854 ~ apiGaliDisswarBidHistoryData ~ totalCount:`, totalCount);



        const result = await gali_disswar_bid_history_module.find(payload).sort({ insert_date: -1 }).skip(skip).limit(limit).lean();

        if (result.length > 0) {
            result.forEach(bid => {
                bid.winning_points = `${bid.winning_points}` || 0,
                    bid.points = `${bid.points}` || 0,
                    bid.status = `${bid.status}`,
                    bid.pay_status = `${bid.pay_status}`,
                    bid.bid_date = new Date(bid.insert_date).toLocaleString('en-IN', {
                        day: '2-digit',
                        month: 'short',
                        year: '2-digit',
                        hour: '2-digit',
                        minute: '2-digit',
                        hour12: true
                    });
            });

            res.json({
                success: true,
                bid_data: result,
                total_count: totalCount,
                msg: 'Bid History Data Available',
            });
        } else {
            res.json({
                success: false,
                bid_data: [],
                total_count: totalCount,
                msg: 'Bid History Data Not Available',
            });
        }
    } catch (err) {
        console.error('apiGaliDisswarBidHistoryData error:', err);
        res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiGaliDisswarWiningHistoryData = async (req, res) => {
    try {
        let {
            // date_from = "", date_to = "",
            page = 1,
            limit = 10
        } = req?.body || {};

        const skip = (page - 1) * limit;


        // date_from = toStr(date_from);
        // date_to = toStr(date_to);

        // if (!date_from && !date_to) {
        //     return res.status(400).json({ success: false, msg: 'All fields are required.' });
        // }

        const userData = req?.user || null;
        if (!userData) {
            return res.json({ success: false, msg: 'User not found' });
        }

        let matchStage = {
            userDB_id: userData._id,
            amount_status: 8
        };

        // if (date_from && date_to) {
        //     const from = new Date(date_from);
        //     const to = new Date(date_to);
        //     to.setHours(23, 59, 59, 999);
        //     matchStage.insert_date = { $gte: from, $lte: to };
        // } else {
        //     const today = new Date();
        //     const start = new Date(today.setHours(0, 0, 0, 0));
        //     const end = new Date(today.setHours(23, 59, 59, 999));
        //     matchStage.insert_date = { $gte: start, $lte: end };
        // }


        const gali_disswar_game_ids = await gali_disswar_games_module.find({}, { _id: 1 });
        console.log("🚀 ~ apiGaliDisswarWiningHistoryData ~ gali_disswar_game_ids:", gali_disswar_game_ids);

        if (gali_disswar_game_ids.length > 0) {
            // Extract just the _id values for $in
            const gameIds = gali_disswar_game_ids.map(game => game._id);
            matchStage.jackpot_gameDB_id = { $in: gameIds };
        }

        console.log("🚀 ~ apiGaliDisswarWiningHistoryData ~ matchStage:", matchStage);

        const totalCount = await wallet_trans_history_module.countDocuments(matchStage);
        console.log("🚀 ~ apiGaliDisswarWiningHistoryData ~ total");

        const records = await wallet_trans_history_module.find(matchStage).sort({ insert_date: -1 }).skip(skip).limit(limit).lean();
        console.log("🚀 ~ apiGaliDisswarWiningHistoryData ~ records:", records)
        // console.log("🚀 ~ apiGaliDisswarWiningHistoryData ~ records:", records)

        const finalResult = await Promise.all(records.map(async (record) => {
            const bidInfo = await gali_disswar_bid_history_module.findOne({ bid_tx_id: record?.bid_tx_id });
            console.log("🚀 ~ apiGaliDisswarWiningHistoryData ~ bidInfo:", bidInfo)

            const options = {
                day: '2-digit',
                month: 'short',
                year: 'numeric',
                hour: '2-digit',
                minute: '2-digit',
                hour12: true,
                timeZone: 'Asia/Kolkata'
            };
            const wining_date = new Date(record.insert_date).toLocaleString('en-IN', options);

            return {
                amount: `${record.amount}`,
                transaction_type: `${record.transaction_type}`,
                transaction_note: record.transaction_note,
                amount_status: `${record.amount_status}`,
                tx_request_number: record.tx_request_number,
                wining_date: wining_date,
                game_name: bidInfo?.game_name || null,
                pana: bidInfo?.pana || null,
                session: bidInfo?.session || null,
                digits: bidInfo?.digits || null,
            };
        }));

        console.log("🚀 ~ apiGaliDisswarWiningHistoryData ~ finalResult:", finalResult)

        if (finalResult.length > 0) {
            res.json({
                success: true,
                win_data: finalResult,
                total_count: totalCount,
                msg: 'Wining History Data Available',
            });
        } else {
            res.json({
                success: false,
                win_data: [],
                total_count: totalCount,
                msg: 'No Wining History Found',
            });
        }

    } catch (err) {
        console.error('apiGaliDisswarWiningHistoryData error:', err);
        res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};


// middleware not used for JWT token
const apiDisawarResultHistoryData = async (req, res) => {
    try {
        let { app_key = '', env_type = '', bid_from = '' } = req?.body || {};

        app_key = toStr(app_key);
        env_type = toStr(env_type);

        if (!app_key || !env_type || !bid_from) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res.json({ success: false, msg: 'UnAuthorized request' });
        }

        let resultDate;
        if (bid_from === '') {
            resultDate = new Date().toISOString().split('T')[0]; // today's date (YYYY-MM-DD)
        } else {
            resultDate = new Date(bid_from).toISOString().split('T')[0];
        }

        const rawResults = await gali_disswar_game_result_history_module.find({ result_date: resultDate });

        const results = await Promise.all(rawResults.map(async (item) => {
            const gameInfo = await gali_disswar_games_module.findOne({ gameDB_id: item.gameDB_id });

            return {
                open_number: item.open_number,
                game_name: gameInfo?.game_name || null,
                game_name_hindi: gameInfo?.game_name_hindi || null
            };
        }));

        if (results.length > 0) {
            res.json({
                success: true,
                Result_data: results,
                msg: 'Result History Data Available',
            });
        } else {
            res.json({
                success: false,
                Result_data: [],
                msg: 'Result History Data Not Available',
            });
        }
    } catch (err) {
        console.error('apiDisawarResultHistoryData error:', err);
        res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiRouletteGame = async (req, res) => {
    try {
        const userData = req?.user || null;
        if (!userData) {
            return res.status(404).json({ success: false, msg: "User not found" });
        }

        const now = new Date();
        const currentTime = now.toTimeString().slice(0, 8); // HH:mm:ss
        const todayDate = now.toISOString().slice(0, 10); // YYYY-MM-DD

        // Fetch active results (upcoming markets)
        const active_result = await roulette_game_module
            .find({ status: 1, close_time_sort: { $gt: currentTime } })
            .sort({ open_time_sort: 1 });

        for (let rs of active_result) {
            if (rs.market_status === 0) {
                rs.msg = 'Market is closed for today';
                rs.msg_hindi = 'à¤¬à¥‡à¤Ÿà¥€à¤¨à¥à¤— à¤†à¤œ à¤•à¥‡ à¤²à¤¿à¤ à¤¬à¤‚à¤¦ à¤¹à¥ˆ';
                rs.msg_status = 2;
            } else {
                const msgData = getMsgAccordingToTimeRouletteActive(rs.open_time, rs.close_time);
                rs.msg = msgData.msg;
                rs.msg_hindi = msgData.msg_hindi;
                rs.msg_status = msgData.msg_status;
            }
            delete rs.market_status;
        }

        const games = await roulette_game_module.find({ status: 1 }).sort({ open_time_sort: 1 });

        const dec_result = await Promise.all(games.map(async (game) => {
            const resultInfo = await roulette_results.findOne({
                gameDB_id: game.gameDB_id,
                result_date: todayDate
            });

            return {
                gameDB_id: game.gameDB_id,
                game_name: game.game_name,
                open_time: game.open_time,
                open_time_sort: game.open_time_sort,
                close_time: game.close_time,
                market_status: game.market_status,
                result: resultInfo?.number || null
            };
        }));


        for (let rs of dec_result) {
            if (!rs.result) rs.result = '';

            if (rs.market_status === 0) {
                rs.msg = 'Market closed';
                rs.msg_hindi = 'à¤¬à¤¾à¤œà¤¾à¤° à¤¬à¤‚à¤¦';
                rs.msg_status = 2;
            } else {
                const msgData = getMsgAccordingToTimeRouletteActive(rs.open_time, rs.close_time);
                rs.msg = msgData.msg;
                rs.msg_hindi = msgData.msg_hindi;
                rs.msg_status = msgData.msg_status;
            }
            delete rs.market_status;
        }

        res.json({
            success: true,
            active_result,
            declare_result: dec_result,
            msg: 'Success',
        });
    } catch (error) {
        console.error('apiRouletteGame error:', error);
        res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

// middleware not used for JWT token
const apiCheckRouletteGameStatus = async (req, res) => {
    try {
        const { app_key = '', env_type = '', gameDB_id = "" } = req?.body || {};
        app_key = toStr(app_key);
        env_type = toStr(env_type);
        gameDB_id = toStr(gameDB_id);

        if (!app_key || !env_type || !gameDB_id) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res.json({ success: false, msg: 'UnAuthorized request' });
        }

        if (!mongoose.isValidObjectId(gameDB_id)) {
            return res.status(400).json({ success: false, msg: "Invalid ID" });
        }

        const game = await roulette_game_module
            .findOne({ gameDB_id })
            .lean();
        if (!game) {
            return res.json({ success: false, msg: 'Game not found' });
        }

        // 3) Parse â€œhh:mm AM/PMâ€ into a Date for today
        const parseTime = (timeStr) => {
            const now = new Date();
            const [timePart, meridiem] = timeStr.split(' ');
            let [hours, minutes] = timePart.split(':').map(Number);
            if (meridiem === 'PM' && hours < 12) hours += 12;
            if (meridiem === 'AM' && hours === 12) hours = 0;
            const today = now.toISOString().slice(0, 10); // "YYYY-MM-DD"
            return new Date(`${today}T${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:00`);
        };

        const now = new Date();
        const openDt = parseTime(game.open_time);
        const closeDt = parseTime(game.close_time);

        let data = {};
        if (now >= openDt && now <= closeDt) {
            data.msg = 'Betting is running for today';
            data.msg_hindi = 'à¤¬à¥‡à¤Ÿà¥€à¤¨à¥à¤— à¤†à¤œ à¤•à¥‡ à¤²à¤¿à¤ à¤¬à¤‚à¤¦ à¤¹à¥ˆ';
            data.game_status = 1;
            data.success = true;
        } else {
            data.msg = 'Market Closed';
            data.msg_hindi = 'à¤¬à¤¾à¤œà¤¾à¤° à¤¬à¤‚à¤¦';
            data.game_status = 2;
            data.success = false;
        }

        return res.json(data);
    } catch (err) {
        console.error('apiCheckRouletteGameStatus error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiGetRouletteGameInfo = async (req, res) => {
    try {
        let { gameDB_id = "" } = req?.body || {};
        gameDB_id = toStr(gameDB_id);

        if (!gameDB_id) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        if (!mongoose.isValidObjectId(gameDB_id)) {
            return res.status(400).json({ success: false, msg: "Invalid ID" });
        }

        const gameTimes = await roulette_game_module
            .findOne({ gameDB_id })
        if (!gameTimes) {
            return res.json({ success: false, msg: 'Game not found' });
        }

        const now = new Date();
        const todayStr = now.toISOString().slice(0, 10); // "YYYY-MM-DD"

        const parseTime = (timeStr) => {
            const [timePart, meridian] = timeStr.split(' ');
            let [hours, minutes] = timePart.split(':').map(Number);
            if (meridian === 'PM' && hours < 12) hours += 12;
            if (meridian === 'AM' && hours === 12) hours = 0;
            const hh = String(hours).padStart(2, '0');
            const mm = String(minutes).padStart(2, '0');
            return new Date(`${todayStr}T${hh}:${mm}:00`);
        };

        const closeDt = parseTime(gameTimes.close_time);
        const diffSecTotal = Math.max(0, Math.floor((closeDt - now) / 1000));
        const min = Math.floor(diffSecTotal / 60);
        const web_time = diffSecTotal;
        const sec = Math.max(0, web_time - 60);

        const bidData = await roulette_bid_history_module
            .find({
                gameDB_id,
                userDB_id: userData._id,
                bid_date: todayStr
            })

        return res.json({
            success: true,
            wallet_amt: userData.wallet_balance,
            account_block_status: userData.status,
            bid_data: bidData,
            min,
            duration: sec * 1000,
            web_time_duration: (web_time - sec) * 1000,
            msg: 'Success',
        });
    } catch (err) {
        console.error('apiGetRouletteGameInfo error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiRouletteSubmitBid = async (req, res) => {
    try {
        let {
            gameDB_id = "",
            game_name = "",
            digits = "",
            points = ""
        } = req?.body || {};

        gameDB_id = toStr(gameDB_id);
        game_name = toStr(game_name);
        digits = Number(toStr(digits));
        points = Number(toStr(points));

        if (!gameDB_id || !game_name || !digits || !points) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        const userData = req?.user || null;
        if (!userData) {
            return res.json({ success: false, msg: 'User not found' });
        }

        if (!mongoose.isValidObjectId(gameDB_id)) {
            return res.status(400).json({ success: false, msg: "Invalid ID" });
        }

        const game = await roulette_game_module
            .findOne({ gameDB_id })
        if (!game) {
            return res.json({ success: false, msg: 'Game not found' });
        }

        const now = new Date();
        const today = now.toISOString().slice(0, 10); // YYYY-MM-DD
        const parseTime = (t) => {
            const [timePart, mer] = t.split(' ');
            let [h, m] = timePart.split(':').map(Number);
            if (mer === 'PM' && h < 12) h += 12;
            if (mer === 'AM' && h === 12) h = 0;
            return new Date(`${today}T${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}:00`);
        };
        const openDt = parseTime(game.open_time);
        const closeDt = parseTime(game.close_time);
        let msg, game_status;
        const diffSec = Math.floor((closeDt - now) / 1000);
        if (now >= openDt && now < closeDt && diffSec >= 60) {
            msg = 'Market Running';
            game_status = 1;
        } else {
            msg = 'Betting is closed for today';
            game_status = 2;
        }

        if (game_status !== 1) {
            return res.json({ success: false, msg });
        }

        if (userData._id < points) {
            return res.json({
                success: false,
                msg: "Sorry You Don't Have Sufficient Amount For This Bid",
            });
        }

        const bidDateStr = today; // assume bid_date stored as 'YYYY-MM-DD'
        const existing = await roulette_bid_history_module.findOne({
            gameDB_id,
            userDB_id: userData._id,
            digits,
            bid_date: bidDateStr
        }).lean();

        if (existing) {
            const oldPoints = existing.points;
            const bidId = existing._id;
            const txId = existing.bid_tx_id;

            userData.wallet_balance = userData.wallet_balance - points + oldPoints;
            await userData.save()

            await roulette_bid_history_module.updateOne(
                { _id: bidId },
                { points, digits }
            );

            await wallet_trans_history_module.updateOne(
                { tx_request_number: txId },
                { amount: points }
            );

        } else {
            const bid_tx_id = getUserRandomToken();
            await roulette_bid_history_module.create({
                userDB_id: userData._id,
                gameDB_id,
                game_name,
                digits,
                points,
                bid_date: bidDateStr,
                bid_tx_id,
                insert_date: new Date()
            });

            userData.wallet_balance -= points;
            userData.save()

            await wallet_trans_history_module.create({
                userDB_id: userData._id,
                amount: points,
                transaction_type: 2,
                transaction_note: `Bid Placed For ${game_name}`,
                amount_status: 5,
                tx_request_number: bid_tx_id,
                insert_date: new Date()
            });
        }

        return res.json({ success: true, msg: 'Bid Successfully Submitted' });

    } catch (error) {
        console.error('apiRouletteSubmitBid error:', error);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiGetRouletteGameWinningNumber = async (req, res) => {
    try {
        let { gameDB_id = "" } = req?.body || {};

        gameDB_id = toStr(gameDB_id);

        if (!gameDB_id) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        if (!mongoose.isValidObjectId(gameDB_id)) {
            return res.status(400).json({ success: false, msg: "Invalid ID" });
        }

        let filter = { gameDB_id };
        if (gameDB_id) {
            const today = new Date().toISOString().slice(0, 10);
            filter.result_date = today;
        }
        const resultRow = await roulette_result_hisory_module.findOne(filter);

        let data = {};
        if (resultRow) {
            data.success = true;
            const winning_number = resultRow.number;
            data.msg = 'Result declared';
            data.winning_number = winning_number;

            const todayStr = new Date().toISOString().slice(0, 10);
            const bidWin = await roulette_bid_history_module.findOne({
                gameDB_id,
                userDB_id: userData._id,
                digits: winning_number,
                bid_date: todayStr
            });
            data.winning_status = bidWin ? 1 : 0;

        } else {
            data.success = false;
            data.msg = 'Result not declared yet';
            data.winning_status = 0;
        }

        const game = await roulette_game_module.findOne({ gameDB_id });
        let min = 0;
        if (game) {
            const now = new Date();
            const today = now.toISOString().slice(0, 10);
            const [h, m] = game.close_time.split(/[: ]/); // ["HH","MM","AM/PM"]
            let hours = parseInt(h, 10), mins = parseInt(m, 10);
            const mer = game.close_time.split(' ')[1];
            if (mer === 'PM' && hours < 12) hours += 12;
            if (mer === 'AM' && hours === 12) hours = 0;
            const closeDt = new Date(`${today}T${String(hours).padStart(2, '0')}:${String(mins).padStart(2, '0')}:00`);
            const diffMs = closeDt - now;
            if (diffMs > 0) {
                min = Math.floor(diffMs / 60000);
            }
        }

        data.min = min;
        data.duration = min * 60000;

        return res.json(data);
    } catch (err) {
        console.error('apiGetRouletteGameWinningNumber error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiRouletteBidHistoryData = async (req, res) => {
    try {
        let { bid_from = "", bid_to = "" } = req?.body || {};

        bid_from = toStr(bid_from);
        bid_to = toStr(bid_to);

        if (!bid_from && !bid_to) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        const userData = req?.user || null;
        if (!userData) {
            return res.status(404).json({ success: false, msg: 'User not found' });
        }

        let dateFilter;
        if (bid_from && bid_to) {
            const from = new Date(bid_from);
            const to = new Date(bid_to);
            to.setHours(23, 59, 59, 999);
            dateFilter = { $gte: from, $lte: to };
        } else {
            const today = new Date();
            const start = new Date(today.setHours(0, 0, 0, 0));
            const end = new Date(today.setHours(23, 59, 59, 999));
            dateFilter = { $gte: start, $lte: end };
        }

        const bids = await roulette_bid_history_module
            .find({ userDB_id: userData._id, bid_date: dateFilter })


        const formatted = bids.map(b => ({
            game_name: b.game_name,
            digits: b.digits,
            points: b.points,
            bid_tx_id: b.bid_tx_id,
            bid_date: new Date(b.insert_date).toLocaleString('en-IN', {
                day: '2-digit',
                month: 'short',
                year: 'numeric',
                hour: 'numeric',
                minute: 'numeric',
                second: 'numeric',
                hour12: true
            })
        }));

        if (formatted.length > 0) {
            res.json({
                success: true,
                bid_data: formatted,
                msg: 'Bid History Data Available',
            });
        } else {
            res.json({
                success: false,
                bid_data: [],
                msg: 'Bid History Data Not Available',
            });
        }
    } catch (err) {
        console.error('apiRouletteBidHistoryData error:', err);
        res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiGetSpDPMotorCombination = async (req, res) => {
    try {
        let {
            type = "",
            number = '',
            points = 0
        } = req?.body || {};

        type = Number(toStr(type));
        number = Number(toStr(number));
        points = Number(toStr(points));

        if (!type || !number || !points) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        const userData = req?.user || null;
        if (!userData) return res.status(404).json({ success: false, msg: 'User not found' });

        const chars = number.split('');
        const output = getPossibleCombination(chars, 3);

        const tb = type === 8 ? single_pana_numbers_module : double_pana_numbers_module;
        const found = [];
        for (const comb of output) {
            const doc = await tb.findOne({ numbers: comb });
            if (doc) found.push(doc.numbers);
        }
        const possible_array = Array.from(new Set(found));

        if (possible_array.length === 0) {
            return res.json({ success: false, msg: 'No Possible combination found' });
        }

        const total_bid_amount = possible_array.length * points;

        if (total_bid_amount > userData.wallet_balance) {
            return res.json({
                success: false,
                msg: "You don't have sufficient balance to place this bid",
            });
        }

        const posssible_array = possible_array.map(num => ({
            number: num,
            points
        }));

        return res.json({
            success: true,
            posssible_array,
            total_bid_amount,
            wallet_amt_after_bid: userData.wallet_balance - total_bid_amount,
        });
    } catch (err) {
        console.error('apiGetSpDPMotorCombination error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

const apiGetSpDpTpCombination = async (req, res) => {
    try {
        let {
            number = '',
            sp_flag = "",
            dp_flag = "",
            tp_flag = "",
            points = 0
        } = req?.body || {};

        number = Number(toStr(number));
        sp_flag = toStr(sp_flag);
        dp_flag = toStr(dp_flag);
        tp_flag = toStr(tp_flag);
        points = Number(toStr(points));

        if (!number || !sp_flag || !dp_flag || !tp_flag || !points) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        const userData = req?.user || null;
        console.log("🚀 ~ apiStarlineSubmitBid ~ userData:", userData)
        console.log("🚀 ~ apiStarlineSubmitBid ~ userData:", userData)

        console.log(`(((((((()))))) ~ mobileController.js:7247 ~ apiWinningHistoryData ~ userData:`, userData);

        console.log(`(((((((()))))) ~ mobileController.js:7246 ~ apiWinningHistoryData ~ userData:`, userData);

        console.log(`(((((((()))))) ~ mobileController.js:7246 ~ apiWinningHistoryData ~ userData:`, userData);

        console.log(`(((((((()))))) ~ mobileController.js:7246 ~ apiWinningHistoryData ~ userData:`, userData);
        if (!userData) return res.json({ success: false, msg: 'User not found' });

        const combos = [];
        const panas = [];

        if (sp_flag === 1) {
            const sp = await single_pana_numbers_module
                .find({ single_digit: number })
            sp.forEach(doc => {
                combos.push(doc.numbers);
                panas.push('Single Pana');
            });
        }

        if (dp_flag === 1) {
            const dp = await double_pana_numbers_module
                .find({ single_digit: number })
            dp.forEach(doc => {
                combos.push(doc.numbers);
                panas.push('Double Pana');
            });
        }

        if (tp_flag === 1) {
            const tp = await tripple_pana_numbers_module.find()
            tp.forEach(doc => {
                const sum = doc.numbers.split('').reduce((acc, d) => acc + Number(d), 0);
                const last = sum > 9 ? sum % 10 : sum;
                if (last === Number(number)) {
                    combos.push(doc.numbers);
                    panas.push('Triple Pana');
                }
            });
        }

        if (combos.length === 0) {
            return res.json({ success: false, msg: 'No Possible combination found' });
        }

        const total_bid_amount = combos.length * points;
        if (total_bid_amount > userData.wallet_balance) {
            return res.json({
                success: false,
                msg: "You don't have sufficient balance to place this bid",
            });
        }

        const posssible_array = combos.map((num, idx) => ({
            number: num,
            points,
            pana: panas[idx]
        }));

        return res.json({
            success: true,
            posssible_array,
            total_bid_amount,
            wallet_amt_after_bid: userData.wallet_balance - total_bid_amount,
        });
    } catch (err) {
        console.error('apiGetSpDpTpCombination error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

// desable this function
const rouletteResultDeclare = async () => {
    try {
        const resultDate = new Date().toISOString().slice(0, 10); // YYYY-MM-DD
        let declareDate = new Date();
        let gameDB_id;

        const todayLast = await roulette_result_hisory_module.findOne({ result_date: resultDate });

        if (todayLast && todayLast.gameDB_id) {
            gameDB_id = todayLast.gameDB_id;
        } else {
            const last = await roulette_result_hisory_module
                .findOne()
                .sort({ result_date: -1 })

            if (last && String(last.gameDB_id) === 'someObjectIdFor95') {
                // Replace 'someObjectIdFor95' with actual ObjectId string of 95
                gameDB_id = mongoose.Types.ObjectId('someObjectIdFor96'); // set new ObjectId manually
                declareDate = new Date(Date.now() - 10_000);
            } else {
                gameDB_id = mongoose.Types.ObjectId('someObjectIdFor1'); // reset to first game
            }
        }

        // 3) Only declare if not already declared
        const exists = await roulette_result_hisory_module.countDocuments({ gameDB_id, result_date: resultDate });
        if (exists === 0) {
            // 4) Find active bids for that game & date
            const pendingBids = await rouletteBidHistoryModel
                .find({ gameDB_id, bid_date: resultDate, pay_status: 0 })
                .lean();

            let winDigits, openResultToken = uniqRandom(15);

            if (pendingBids.length > 0) {
                // 5) Determine winning digit: least total points or default
                const digitsPlayed = [...new Set(pendingBids.map(b => b.digits))];

                // a) pipeline for default digits not played
                const missingPipeline = [
                    { $match: { digit_id: { $nin: digitsPlayed } } },
                    { $project: { digits: '$digit_id', points: '$digit_value' } }
                ];
                // b) pipeline for played digits, sum points
                const playedPipeline = [
                    { $match: { gameDB_id, bid_date: resultDate } },
                    { $group: { _id: '$digits', points: { $sum: '$points' } } },
                    { $project: { digits: '$_id', points: 1 } }
                ];
                // c) union, sort by points, limit 1
                const [{ digits: chosen, points: minPoints }] = await digitModel
                    .aggregate([
                        { $facet: { missing: missingPipeline, played: playedPipeline } },
                        { $project: { union: { $concatArrays: ['$missing', '$played'] } } },
                        { $unwind: '$union' },
                        { $replaceRoot: { newRoot: '$union' } },
                        { $sort: { points: 1 } },
                        { $limit: 1 }
                    ]);

                winDigits = chosen;

                // 6) Pay winners
                for (const bid of await rouletteBidHistoryModel.find({
                    gameDB_id: gameId,
                    bid_date: resultDate,
                    digits: winDigits,
                    pay_status: 0
                }).lean()) {
                    const winAmt = 10 * bid.points;
                    // increment user wallet
                    await userModel.updateOne(
                        { unique_token: bid.unique_token },
                        { $inc: { wallet_balance: winAmt } }
                    );
                    // record transaction
                    await transactionHistoryModel.create({
                        user_id: bid.user_id,
                        amount: winAmt,
                        transaction_type: 1,
                        transaction_note: `Amount won in Roulette for Bid- ${bid.bid_tx_id}`,
                        amount_status: 81,
                        tx_request_number: getUserRandomToken(),
                        open_result_token: openResultToken,
                        bid_tx_id: bid.bid_tx_id,
                        insert_date: declareDate
                    });
                    // mark bid as paid
                    await rouletteBidHistoryModel.updateOne(
                        { bid_tx_id: bid.bid_tx_id },
                        { pay_status: 1, result_token: openResultToken }
                    );
                }
            } else {
                // 7) No bids â†’ random digit
                winDigits = Math.floor(Math.random() * 10);
            }

            // 8) Insert result declaration
            await roulette_result_hisory_module.create({
                game_id: gameId,
                number: winDigits,
                result_date: resultDate,
                result_token: openResultToken,
                declare_date: declareDate
            });
        }
    } catch (err) {
        console.error('rouletteResultDeclare error:', err);
    }
};

const apiChatApp = async (req, res) => {
    try {
        // let { msg = '' } = req.body;

        // msg = toStr(msg)

        // if (!msg) {
        //     return res.status(400).json({ success: false, msg: 'Message is required' });
        // }

        if (!req.file || !req.file.buffer) {
            return res.status(400).json({ success: false, msg: 'File type invalid or missing' });
        }

        const fileBuffer = req.file.buffer;

        // const userData = req.user;
        // if (!userData) return res.status(404).json({ success: false, msg: 'User not found' });

        const imageDB_id = await new file_module({
            fileInfo: {
                fileBuffer,
                content_type: req.file.mimetype,
            }
        })

        // await chat_msg_module.create({
        //     userDB_id: userData._id,
        //     reply: msg,
        //     file: imageDB_id?._id,
        //     support_id: 1,
        //     reply_type: 2,
        //     insert_date: new Date()
        // });

        await slider_images_module.create({
            image_title: "this is first title",
            display_order: 1,
            slider_image: imageDB_id?._id,
            status: 1,
        });

        return res.json({ success: true, msg: 'Message Successfully Added' });
    } catch (err) {
        console.error('apiChatApp error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};

// middleware not used for JWT token
const apiGetChatApp = async (req, res) => {
    try {
        let { app_key = '', env_type = '' } = req?.body || {};

        app_key = toStr(app_key);
        env_type = toStr(env_type);

        if (!app_key || !env_type) {
            return res.status(400).json({ success: false, msg: 'All fields are required.' });
        }

        if (!checkRequestAuth(app_key, env_type)) {
            return res.json({ success: false, msg: 'UnAuthorized request' });
        }

        const records = await chat_msg_module
            .find({ userDB_id: userData._id })
            .select('support_id reply file reply_type insert_date')
            .sort({ insert_date: 1 })
            .lean();

        if (records.length > 0) {
            const user_data = records.map(r => ({
                reply: r.reply,
                file: r.file ? `base:${r.file.content_type};base64,${r.file.fileBuffer.toString('base64')}` : '',
                insert_date: new Date(r.insert_date).toLocaleDateString('en-IN', {
                    day: '2-digit',
                    month: 'short',
                    year: 'numeric'
                }),
                reply_type: r.reply_type
            }));

            return res.json({
                success: true,
                user_data,
                msg: 'User Detail',
            });
        } else {
            return res.json({
                success: false,
                payment_details: [],
                msg: 'msg not found',
            });
        }
    } catch (err) {
        console.error('apiGetChatApp error:', err);
        return res.status(500).json({ success: false, msg: 'Internal Server Error' });
    }
};



const allGamesResultshistory = async (req, res) => {
    try {
        const {
            app_key = "",
            env_type = "",
            unique_jwt_token = "",
            resultDate = "",
            marketType = "",
        } = req.body;

        if (!resultDate || !marketType) {
            return res.status(400).json({
                success: false,
                msg: "Missing required fields"
            });
        }

        // Date handling (IST to full-day range)
        const istMoment = moment_timeZone.tz(resultDate, "YYYY-MMM-DD", "Asia/Kolkata");
        const startDate = istMoment.clone().startOf('day').toDate();
        const endDate = istMoment.clone().endOf('day').toDate();

        // Identify collections based on marketType
        let gamesCollection, resultsCollection;
        let sessionType = 'single';

        if (marketType === 'mainMarket') {
            gamesCollection = games_module;
            resultsCollection = game_result_history_module;
            sessionType = 'multi';
        } else if (marketType === 'starlineMarket') {
            gamesCollection = starline_games_module;
            resultsCollection = starline_game_result_history_module;
        } else if (marketType === 'jackpotMarket') {
            gamesCollection = gali_disswar_games_module;
            resultsCollection = gali_disswar_game_result_history_module;
        } else {
            return res.status(400).json({
                success: false,
                msg: "Invalid market type"
            });
        }

        // Fetch all games
        const games = await gamesCollection.find({}, { game_name: 1 }).lean();

        // Fetch results of the given day
        const results = await resultsCollection.find({
            result_date: { $gte: startDate, $lte: endDate }
        }).lean();

        // Merge games with results
        const finalData = games.map(game => {
            const result = results.find(r =>
                r.gameDB_id && r.gameDB_id.toString() === game._id.toString()
            );

            // Initialize default structure for consistent response
            const baseStructure = {
                game_name: game.game_name,
                result_number: "",
                open_result: "",
                close_result: "",
                open_decleare_date: "",
                close_decleare_date: ""
            };

            // If result not found, return default structure
            if (!result) return baseStructure;

            // Handle market-specific logic
            if (marketType === 'mainMarket') {
                const openPana = result.open_number || '';
                const closePana = result.close_number || '';

                let openResult = '';
                let closeResult = '';
                let resultNumber = '';

                if (openPana) {
                    const openDigit = openPana.split('').reduce((sum, d) => sum + parseInt(d), 0) % 10;
                    openResult = `${openPana}-${openDigit}`;
                }

                if (closePana) {
                    const closeDigit = closePana.split('').reduce((sum, d) => sum + parseInt(d), 0) % 10;
                    closeResult = `${closeDigit}-${closePana}`;
                }

                if (openResult && closeResult)
                    resultNumber = `${openResult}-${closeResult}`;
                else
                    resultNumber = openResult || closeResult;

                return {
                    ...baseStructure,
                    result_number: resultNumber,
                    open_result: openResult,
                    close_result: closeResult,
                    open_decleare_date: result.open_decleare_date
                        ? moment_timeZone(result.open_decleare_date).format('YYYY-MMM-DD HH:mm:ss')
                        : "",
                    close_decleare_date: result.close_decleare_date
                        ? moment_timeZone(result.close_decleare_date).format('YYYY-MMM-DD HH:mm:ss')
                        : ""
                };
            }

            else if (marketType === 'starlineMarket' || marketType === 'jackpotMarket') {
                const pana = result.open_number || '';
                let resultNumber = '';

                if (pana) {
                    const digit = pana.split('').reduce((sum, d) => sum + parseInt(d), 0) % 10;
                    resultNumber = `${pana}-${digit}`;
                }

                return {
                    ...baseStructure,
                    result_number: resultNumber,
                    open_result: resultNumber,
                    open_decleare_date: result.open_decleare_date
                        ? moment_timeZone(result.open_decleare_date).format('YYYY-MMM-DD HH:mm:ss')
                        : ""
                };
            }

            return baseStructure;
        });

        return res.status(200).json({
            success: true,
            msg: "Data fetched successfully",
            data: finalData,
            market_type: marketType,
            session_type: sessionType
        });

    } catch (error) {
        console.error("❌ Error in allGamesResultshistory:", error);
        return res.status(500).json({
            success: false,
            msg: "Internal server error"
        });
    }
};





const saveFirebaseToken = async (req, res) => {
    try {

        const { firebaseToken } = req?.body;
        console.log("🚀 ~ saveFirebaseToken ~ firebaseToken:", firebaseToken)

        if (!firebaseToken || firebaseToken == '') {
            return res.status(400).json({ success: false, msg: "firebase token required!" });
        }

        const userId = req?.user?._id;
        console.log("🚀 ~ saveFirebaseToken ~ userId:", userId)

        if (!userId) {
            return res.status(400).json({ success: false, msg: "User data not found!" })
        }

        const setFirebaseToken = await user_module.findOneAndUpdate(userId, { firebaseToken }, { new: true });
        console.log("🚀 ~ saveFirebaseToken ~ setFirebaseToken:", setFirebaseToken)

        if (setFirebaseToken) {
            return res.status(200).json({ success: true, msg: "Fire base token stored successfully" })
        } else {
            return res.status(400).json({ success: false, msg: "Somethings went wrong while firebase token storing" })
        }


    } catch (error) {
        console.log("🚀 ~ saveFirebaseToken ~ error:", error)

    }
}



module.exports = {
    appInfoData,
    verifyMpin,
    forgetPasswordMpin,
    changePasswordMpin,
    lobbyData,
    checkToken,
    // gameResultChart,

    gameJodiChart,
    gamePanelChart,
    apiLogout_state_update,
    getPublicImages,
    apiGetAppKey,
    apiCheckMobile,
    apiCheckUsername,
    apiOtpSent,
    apiResendOtp,
    apiUserRegistration,
    apiUserStatus,
    apiUserLogin,
    apiCheckUserDeviceId,
    apiChangePassword,
    apiUpdatePin,
    apiForgotPin,
    apiForgotPassword,
    apiForgetCheckmobile,
    apiGetState,
    apiGetDistrict,
    apiAddUserAddress,
    apiGetUserAddress,
    apiGetProfile,
    apiProfileUpdate,
    apiCheckSecurityPin,
    apiAdminBankDetails,
    apiFundRequestAdd,
    apiLastFundRequestDetail,
    apiFundPaymentSlipUpload,
    apiAddUserBankDetails,
    apiUserBankDetails,
    apiAddUserUpiDetails,
    apiGetUserPaymentDetails,
    apiGameRates,
    apiFundRequestHistory,
    apiUserWalletBalance,
    apiCheckUserForTransferAmt,
    apiUserTransferWalletBalance,
    apiUserPaymentMethodList,
    apiUserWithdrawFundRequest,
    apiGetBellNotification,
    apiCheckNotificationDot,
    apiHowToPlay,
    apiWalletTransactionHistory,
    apiPassbookBidDataInfo,
    apiViewWalletTransactionHistory,
    apiUserWithdrawTransactionHistory,
    apidepositwithdrawHistoryData,
    apiGetAutoDepositList,
    apiGetSocialData,
    apiValidateBank,
    apiGetDashboardData,
    apiGetUpdateResult,
    apiGetLotteryData,
    apiGetSliderImages,
    apiGetCurrentDate,
    apiCheckGamesActiveInactive,
    apiSubmitBid,
    apiLotteryBid,
    apiLotteryPayment,
    apiBidHistoryData,
    // apiMainBidHistoryData,
    // apiStarLineBidHistoryData, //
    apiStarlineBidHistoryData, //
    apiJackpotBidHistoryData,
    apiGetContactDetails,
    apiSubmitContactUs,
    apiGetNotification,
    apiUpdateUserNotificationControl,
    apiSubmitIdea,
    apiWinningHistoryData,
    apiGetTipsList,
    apiViewTipsDetails,
    apiCheckGameStatus,
    apiNotificationSetting,
    apiGetStatement,
    apiAddMoneyViaUpi,
    checkNotification,
    apiGetAppVersionDetails,
    apiStarlineGameRates,
    apiStarlineGame,
    apiCheckStarLineGameStatus,
    apiCheckStarLineGamesActiveInactive,
    apiStarlineSubmitBid,
    apiStarlineWiningHistoryData,
    apiStarlineGameNames,
    apiStarlineResultHistoryData,
    apiGaliDisswarGameRates,
    apiGaliDisswarGame,
    apiCheckGaliDisswarGameStatus,
    apiCheckGaliDisswarGamesActiveInactive,
    apiGaliDisswarSubmitBid,
    apiGaliDisswarBidHistoryData,
    apiGaliDisswarWiningHistoryData,
    // apiDisswargamenames,
    apiDisawarResultHistoryData,
    apiRouletteGame,
    apiCheckRouletteGameStatus,
    apiGetRouletteGameInfo,
    apiRouletteSubmitBid,
    apiGetRouletteGameWinningNumber,
    apiRouletteBidHistoryData,
    apiGetSpDPMotorCombination,
    apiGetSpDpTpCombination,
    rouletteResultDeclare,
    apiChatApp,
    apiGetChatApp,
    apiGetQRCode,
    gameResultChart_details,
    gameResult_galidessar_chart_details,
    allGamesResultshistory,
    saveFirebaseToken,
    verifyForgetOtp



};