const express = require('express'); //requires express module
const mongoose = require("mongoose");
const socket = require('socket.io'); //requires socket.io module
// Assuming you have a connection to the notification server
const notificationSocket = require('socket.io-client')('http://starapi.stararabgroup.com:3008');

const fs = require('fs');
var mysql = require('mysql');
const app = express();
var PORT = process.env.PORT || 1772;
const server = app.listen(PORT); //tells to host server on localhost:3000


//Playing variables:
app.use(express.static('public')); //show static files in 'public' directory

const User = require("./model/user.model");
const Payment = require("./model/payment.model");

const Lucky77Table = require("./model/lucky77_table.model");
const Lucky77Bid = require("./model/lucky77_bid.model");
const AppSetting = require("./model/appSetting.model");
const GameTransaction = require("./model/gameTransaction.model");

console.log('Server is running');
const io = socket(server, {
  cors: {
    origin: "*",
  }
});


mongoose.connect(
    `mongodb+srv://mohammad:FlvC33mQ3LZoBNHx@cluster0.jxnn5.mongodb.net/stararabchat_prod`,

    {
        useNewUrlParser: true,
        useUnifiedTopology: true,
    }
);

const db = mongoose.connection;

db.on("error", console.error.bind(console, "connection error:"));
db.once("open", () => {
    console.log("MONGO: successfully connected to db");
});

let customRes = false;
let result = 0;
let seat_1 = 0;
let seat_2 = 0;
let seat_3 = 0;
let actual_seat_1 = 0;
let actual_seat_2 = 0;
let actual_seat_3 = 0;
let count = Math.floor(Date.now()/1000)-((Math.floor(Math.floor(Date.now()/1000)/30))*30);
let status = count < 20 ? 1 : (count < 25 ? 2 : 3);
let counter = count < 20 ? 20-count : (count < 25 ?  5-(count-20) : 5-(count-25));
let sessionId = (Math.floor(Math.floor(Date.now()/1000)/30));
let bidders = {};
//Socket.io Connection------------------
io.on('connection', async (socket) => {
    let uid = 0;
    console.log("New socket connection: " + socket.id)
    socket.on('join', function (data) {    
        socket.join(data);
        uid = data;
        console.log("join: "+uid);
        if (uid == 1614626426) {
            console.log("banned join: "+uid);
            socket.disconnect(true);
        }
    });
    let history = [];
    const lucky77History = await Lucky77Table.aggregate([
        {
            $match: {
                session: { $lt: sessionId } // Replace with actual sessionId ObjectId
            }
        },
        {
            $sort: { session: -1 } // Sort by session in descending order
        },
        {
            $limit: 15 // Limit results to 15 documents
        },
        {
            $project: {
                result: 1, // Include only the "result" field
                session: 1 // Convert session ObjectId to string
            }
        }
    ]);

    for (const value of lucky77History) {
        const index = lucky77History.indexOf(value);
        history.push(value.result);
    }
    io.emit('history', {"history": history});
    
    socket.on('setResult', data => {
        if (status < 2) {
            result = data;
            customRes = true
            io.emit("setResultRes", result);
        }
    });
    
    let myBiddingSeat_1 = 0;
    let myBiddingSeat_2 = 0;
    let myBiddingSeat_3 = 0;
    
    let userUid = 0;
    let userId = 0;
    let userName = "";
    let userImage = "";
    
    let oldOwnStatus = 0;
    let notBet = true;
    var t=setInterval(async function () {
        sessionId = (Math.floor(Math.floor(Date.now()/1000)/30));
        count = Math.floor(Date.now()/1000)-((Math.floor(Math.floor(Date.now()/1000)/30))*30);
        const Ownstatus = count < 20 ? 1 : (count < 25 ? 2 : 3);
        if (oldOwnStatus != Ownstatus) {
            io.emit('roundChange', sessionId);
        }
        if (oldOwnStatus != Ownstatus && Ownstatus == 1) {
            notBet = true;
            myBiddingSeat_1 = 0;
            myBiddingSeat_2 = 0;
            myBiddingSeat_3 = 0;
            console.log('update single reset ',userUid);
            io.emit('bidding', {"bidder": userUid,"seat_1": myBiddingSeat_1,"seat_2": myBiddingSeat_2,"seat_3": myBiddingSeat_3,"actual_seat_1": actual_seat_1,"actual_seat_2": actual_seat_2,"actual_seat_3": actual_seat_3});
        }

//        if (oldOwnStatus != Ownstatus && Ownstatus == 2 && notBet) {

        if (Ownstatus == 1 && count > 15 && notBet) {
            notBet = false;
            console.log('status change', 'oldStatus', oldOwnStatus,'newStatus',Ownstatus);
            const totalBids = myBiddingSeat_1+myBiddingSeat_2+myBiddingSeat_3;
            console.log('totalBids',totalBids);
            if (totalBids > 0) {
                console.log(totalBids);
                const user = await User.findOne({uid: userUid});
                if (user) {
                    if (user.balance >= totalBids) {
                        await User.updateOne({uid: userUid},{ $inc: { balance: -totalBids } });
                        const paymentBidding = new Payment();
                        paymentBidding.userId = userUid;
                        paymentBidding.coin = totalBids;
                        paymentBidding.type = 77
                        paymentBidding.isIncome = false;
                        paymentBidding.date = new Date().toLocaleString();
                        paymentBidding.save();

                        const gameTransaction = new GameTransaction();
                        gameTransaction.session = sessionId
                        gameTransaction.uid = userUid;
                        gameTransaction.name = userName;
                        gameTransaction.gameId = 2;
                        gameTransaction.coins = -totalBids;
                        gameTransaction.type = 0;
                        gameTransaction.save();
                        
                        const companyShare = (totalBids)*0.2;
                        const rotationShare = (totalBids)*0.8;
                        const companyBalance = await AppSetting.findOne({ name: 'lucky77_company'});
                        companyBalance.valueInt = companyBalance.valueInt+companyShare;
                        await companyBalance.save();
                        
                        if (myBiddingSeat_1 > 0) {
                            const lucky77Bid = new Lucky77Bid();
                            lucky77Bid.uid = userUid;
                            lucky77Bid.name = userName;
                            lucky77Bid.image = userImage;
                            lucky77Bid.session = sessionId
                            lucky77Bid.amount = myBiddingSeat_1;
                            lucky77Bid.seat = 1;
                            lucky77Bid.save();
                            console.log(' seat 1 bid added for '+userName+' Amount: '+myBiddingSeat_1)
                        }
                        if (myBiddingSeat_2 > 0) {
                            const lucky77Bid = new Lucky77Bid();
                            lucky77Bid.uid = userUid;
                            lucky77Bid.name = userName;
                            lucky77Bid.image = userImage;
                            lucky77Bid.session = sessionId
                            lucky77Bid.amount = myBiddingSeat_2;
                            lucky77Bid.seat = 2;
                            lucky77Bid.save();
                            console.log(' seat 2 bid added for '+userName+' Amount: '+myBiddingSeat_2)
                        }
                        if (myBiddingSeat_3 > 0) {
                            const lucky77Bid = new Lucky77Bid();
                            lucky77Bid.uid = userUid;
                            lucky77Bid.name = userName;
                            lucky77Bid.image = userImage;
                            lucky77Bid.session = sessionId
                            lucky77Bid.amount = myBiddingSeat_3;
                            lucky77Bid.seat = 3;
                            lucky77Bid.save();
                            console.log(' seat 3 bid added for '+userName+' Amount: '+myBiddingSeat_3)
                        }
                        await Lucky77Table.updateOne({session: sessionId},{ $inc: { seat_1: myBiddingSeat_1 } });
                        console.log('updateOne', {session: sessionId},{ $inc: { seat_1: myBiddingSeat_1 } })
                        await Lucky77Table.updateOne({session: sessionId},{ $inc: { seat_2: myBiddingSeat_2 } });
                        console.log('updateOne', {session: sessionId},{ $inc: { seat_2: myBiddingSeat_2 } })
                        await Lucky77Table.updateOne({session: sessionId},{ $inc: { seat_3: myBiddingSeat_3 } });
                        console.log('updateOne', {session: sessionId},{ $inc: { seat_3: myBiddingSeat_3 } })
                    }
                }
            }
        }
        oldOwnStatus = Ownstatus;
    },1000);
    

    socket.on("disconnect", async () => {
        myBiddingSeat_1 = 0;
        myBiddingSeat_2 = 0;
        myBiddingSeat_3 = 0;
    });
    socket.on('bid', async (data) => {
        if (status == 1) {
            const response = JSON.parse(data);
            const bidder = response.uid;
            const bidderId = response.id;
            const amount = response.selectedBidding;
            const seat = response.seat;
            const user = await User.findOne({uid: bidder});
            if (user) {
                if (user.balance >= amount) {
                    userUid = user.uid
                    userName = user.fullname
                    userImage = user.image
                    if (seat == 1) {
                        seat_1 = seat_1+amount
                        actual_seat_1 = actual_seat_1+amount
                        myBiddingSeat_1 = myBiddingSeat_1+amount
                    }
                    else if (seat == 2) {
                        seat_2 = seat_2+amount
                        actual_seat_2 = actual_seat_2+amount
                        myBiddingSeat_2 = myBiddingSeat_2+amount
                    }
                    else if (seat == 3) {
                        seat_3 = seat_3+amount
                        actual_seat_3 = actual_seat_3+amount
                        myBiddingSeat_3 = myBiddingSeat_3+amount
                    }
                    console.log(data)
                    console.log(bidder);
                    console.log(bidderId);
                    console.log(amount);
                    console.log(seat);
                    bidders[bidder] = {"total": myBiddingSeat_1+myBiddingSeat_2+myBiddingSeat_3, "name": userName, "image": userImage};
                    io.emit('sinbid', {"seat": seat,"amount": amount});
                    io.emit('bidding', {"bidder": 0,"seat_1": seat_1,"seat_2": seat_2,"seat_3": seat_3,"actual_seat_1": actual_seat_1,"actual_seat_2": actual_seat_2,"actual_seat_3": actual_seat_3});
                    io.emit('bidding', {"bidder": bidderId,"seat_1": myBiddingSeat_1,"seat_2": myBiddingSeat_2,"seat_3": myBiddingSeat_3,"actual_seat_1": actual_seat_1,"actual_seat_2": actual_seat_2,"actual_seat_3": actual_seat_3});
                };
            };
        }
    })
})

var t=setInterval(async function () {
    const oldStatus = status;
    sessionId = (Math.floor(Math.floor(Date.now()/1000)/30));
    count = Math.floor(Date.now()/1000)-((Math.floor(Math.floor(Date.now()/1000)/30))*30);
    status = count < 20 ? 1 : (count < 25 ? 2 : 3);
    counter = count < 20 ? 20-count : (count < 25 ?  5-(count-20) : 5-(count-25));
    if (status == 1) {
        seat = Math.floor(1 + Math.random()*(3 - 1 + 1));
        amount = Math.floor(1 + Math.random()*(10 - 1 + 1))*10;
        if (seat == 1) {
            seat_1 = seat_1+amount
        }
        else if (seat == 2) {
            seat_2 = seat_2+amount
        }
        else if (seat == 3) {
            seat_3 = seat_3+amount
        }
        io.emit('bidding', {"bidder": 1,"seat_1": seat_1,"seat_2": seat_2,"seat_3": seat_3,"actual_seat_1": actual_seat_1,"actual_seat_2": actual_seat_2,"actual_seat_3": actual_seat_3});
        
        // Convert the object to an array of values
        let biddersArray = Object.values(bidders);
        
        // Sort the array by 'total' in descending order
        biddersArray.sort((a, b) => b.total - a.total);
        
        // Get the top 6 bidders
        let topBidders = biddersArray.slice(0, 6);
        
        // Send the top bidders via Socket.IO
        io.emit('top_bidders', topBidders);
        
    }
    if (oldStatus == 3 && status == 1) {
        bidders = {};
        customRes = false
        result = 0;
        seat_1 = 0;
        seat_2 = 0;
        seat_3 = 0;
        actual_seat_1 = 0;
        actual_seat_2 = 0;
        actual_seat_3 = 0;
        io.emit('bidding', {"bidder": 0,"seat_1": seat_1,"seat_2": seat_2,"seat_3": seat_3,"actual_seat_1": actual_seat_1,"actual_seat_2": actual_seat_2,"actual_seat_3": actual_seat_3});
        io.emit('bidding', {"bidder": 1,"seat_1": 0,"seat_2": 0,"seat_3": 0,"actual_seat_1": 0,"actual_seat_2": 0,"actual_seat_3": 0});
        const newLucky77Table = new Lucky77Table();
        newLucky77Table.session = sessionId;
        newLucky77Table.result = 0;
        newLucky77Table.seat_1 = 0;
        newLucky77Table.seat_2 = 0;
        newLucky77Table.seat_3 = 0;
        await newLucky77Table.save();

        let history = [];
        const lucky77History = await Lucky77Table.aggregate([
            {
                $match: {
                    session: { $lt: sessionId } // Replace with actual sessionId ObjectId
                }
            },
            {
                $sort: { session: -1 } // Sort by session in descending order
            },
            {
                $limit: 15 // Limit results to 15 documents
            },
            {
                $project: {
                    result: 1, // Include only the "result" field
                    session: 1 // Convert session ObjectId to string
                }
            }
        ]);

        for (const value of lucky77History) {
            const index = lucky77History.indexOf(value);
            history.push(value.result);
        }
        io.emit('history', {"history": history});
        if (result == 0) {
            result = Math.floor(1 + Math.random()*(3 - 1 + 1));
            io.emit("setResultRes", result);
        }
    }
    if (oldStatus == 1 && status == 2) {
        console.log(Date.now(),"state result");
        await Lucky77Table.updateOne({session: sessionId},{ $set: { result: result } });
        let top3 = [];
        const lucky77TopBidding = await Lucky77Bid.aggregate([
            {
                $match: {
                    session: sessionId,
                    seat: result
                }
            },
            {
                $group: {
                    _id: "$uid",
                    uid: { $first:"$uid" },
                    name: { $first:"$name" },
                    image: { $first:"$image" },
                    bidAmt: { $sum: "$amount" },
                    winBidAmt: {
                        $sum: {
                            $cond: {
                                if: { $and: [ { $eq: [ "$seat", result ] } ] },
                                then: "$amount",
                                else: 0
                            }
                        }
                    }
                }
            },
            {
                $sort: { winBidAmt: -1 }
            },
            {
                $limit: 3
            }
        ]);
        //for (const value of lucky77Bidding) {
        //    console.log('biddings result',value)
        //    const index = lucky77Bidding.indexOf(value);
        //    const winning = value.winBidAmt*3;
        //    io.emit('myresult', {uid: value.uid, bid: value.bidAmt, win: winning});
        //    if (winning > 0) {
        //        await User.updateOne({uid: value.uid},{ $inc: { balance: winning } });
        //        const paymentWinning = new Payment();
        //        paymentWinning.userId = value.uid;
        //        paymentWinning.coin = winning;
        //        paymentWinning.type = 33
        //        paymentWinning.isIncome = true;
        //        paymentWinning.date = new Date().toLocaleString();
        //        paymentWinning.save();
        //        const premiumMessage = value.name+" won "+winning+" Coins!";
        //        notificationSocket.emit('game_notification', {gameType: 1,message: premiumMessage});
        //    }
        //}
        console.log('lucky77TopBidding');
        console.log(lucky77TopBidding)
        const factors = [2, 8, 2];
        for (const value of lucky77TopBidding) {
            const index = lucky77TopBidding.indexOf(value);
            top3.push({uid: value.uid, name: value.name, image: value.image, bid: value.bidAmt, win: value.winBidAmt*factors[result-1]});
        }
        if (top3.length === 0) {
            top3.push({uid: 0, name: '', image: '', bid: 0, win: 0});
            top3.push({uid: 0, name: '', image: '', bid: 0, win: 0});
            top3.push({uid: 0, name: '', image: '', bid: 0, win: 0});
        }
        else if (top3.length === 1) {
            top3.push({uid: 0, name: '', image: '', bid: 0, win: 0});
            top3.push({uid: 0, name: '', image: '', bid: 0, win: 0});
        }
        else if (top3.length === 2) {
            top3.push({uid: 0, name: '', image: '', bid: 0, win: 0});
        }

        console.log('result', {result: result, highscores: top3});
        io.emit('result', {result: result, highscores: top3});
    }
    if (oldStatus == 2 && status == 3) {
        console.log(Date.now(),"state result");
        await Lucky77Table.updateOne({session: sessionId},{ $set: { result: result } });
        const lucky77Bidding = await Lucky77Bid.aggregate([
            {
                $match: {
                    session: sessionId
                }
            },
            {
                $group: {
                    _id: "$uid",
                    uid: { $first:"$uid" },
                    name: { $first:"$name" },
                    image: { $first:"$image" },
                    bidAmt: { $sum: "$amount" },
                    winBidAmt: {
                        $sum: {
                            $cond: {
                                if: { $and: [ { $eq: [ "$seat", result ] } ] },
                                then: "$amount",
                                else: 0
                            }
                        }
                    }
                }
            }
        ]);
        for (const value of lucky77Bidding) {
            console.log('biddings result',value)
            const index = lucky77Bidding.indexOf(value);
            const factors = [2, 8, 2];
            const winning = value.winBidAmt*factors[result-1];
            io.emit('myresult', {uid: value.uid, name: value.name, image: value.image, bid: value.bidAmt, win: winning});
            if (winning > 0) {
                await User.updateOne({uid: value.uid},{ $inc: { balance: winning } });
                const paymentWinning = new Payment();
                paymentWinning.userId = value.uid;
                paymentWinning.coin = winning;
                paymentWinning.type = 77
                paymentWinning.isIncome = true;
                paymentWinning.date = new Date().toLocaleString();
                paymentWinning.save();
                const gameTransaction = new GameTransaction();
                gameTransaction.session = sessionId
                gameTransaction.uid = value.uid;
                gameTransaction.name = value.name;
                gameTransaction.gameId = 2;
                gameTransaction.coins = winning;
                gameTransaction.type = 1;
                gameTransaction.save();
                if (winning > 5000) {
                const premiumMessage = value.name+" won "+winning+" Coins!";
                notificationSocket.emit('game_notification', {gameType: 1,message: premiumMessage});
                }
            }
        }
    }
    io.emit('counter', counter);
    if (counter <= 5 && status != 3) {
        if (status == 1 && !customRes) {
            customRes = true;
            //result = resultarrs[sessionId % resultarrs.length];
            //io.emit("setResultRes", result);
            const rotationBalance = await AppSetting.findOne({ name: 'lucky77_rotation'});
            const totalBids = actual_seat_1+actual_seat_2+actual_seat_3;
            let rotationShare = Math.floor(totalBids*0.8);
            console.log('rotationShare',rotationShare);
            let maxReward = Math.floor(rotationShare * 8);
            rotationBalance.valueInt = rotationBalance.valueInt+rotationShare;
            if (maxReward > rotationBalance.valueInt) {
                maxReward = rotationBalance.valueInt;
            }
            console.log('rotationBalance',rotationBalance.valueInt);
            console.log('maxReward',maxReward);
            const array = [actual_seat_1*2,actual_seat_2*8,actual_seat_3*2];
            let suitvals = [];
            array.forEach((item, index, arr) => {
                console.log(item,index,arr)
                if (item < maxReward) {
                    suitvals.push(index+1);
                }
            });
            console.log('suitvals',suitvals);
            if (suitvals.length > 0) {
                result = suitvals[Math.floor(Math.random()*(suitvals.length))];
                console.log('final result suit', result);
                io.emit("setResultRes", result);
            }
            else {
                let largest = array[0];
                let largestIndex = 1;
                array.forEach((item, index, arr) => {
                    console.log(item,index,arr)
                    if (item < largest) {
                        largest = item;
                        largestIndex = index+1;
                        result = largestIndex;;
                    }
                });
                console.log('final result random', result);
                io.emit("setResultRes", result)
            }
            rotationBalance.valueInt = rotationBalance.valueInt-array[result-1];
            console.log('add reward',rotationBalance.valueInt)
            await rotationBalance.save();
        }
        io.emit('status', 2);
    }
    else {
        io.emit('status', status);
    }
},1000);