const User = require('../models/User');
const UsersDailySteps = require('../models/UsersDailySteps');
const UsersDailyAdds = require('../models/UsersDailyAdds');
const UserTokens = require('../models/UserTokens');
const TokenMintHistory = require('../models/TokenMintHistory');
const TotalIssuesToken = require('../models/TotalIssuesToken');
const UserWithdrawals = require('../models/UserWithdrawals');
const Tokenomics = require('../models/Tokenomics');

const authService = require('../../services/auth.service');
const helperService = require('../../services/helpers.service');
const emailService = require('../../services/email.service');

const { includes } = require('lodash');
const Sequelize = require('sequelize');

const sequelize = require('../../config/database');
exports.stepCount = async (req, res) => {
    const { token, steps, date } = req.body;
    console.log('steps::::::::', steps)
    if (token) {
      authService().verify(token, async (err, data) => {
        if (err) {
          return helperService().unauthorized(res);
        }
        try{
            const user_id = data.user_id
            // get daily steps
            const getUser = await User.findOne({
            where: {
                id: user_id,
                status: 1
            },
            });

            const usersDailySteps = await UsersDailySteps.findOne({
            where: {
                date: date,
                user_id,
            },
            });
            
            // get adds steps
            const getAdds = await UsersDailyAdds.findOne({
            where: {
                date: date,
                user_id,
            },
                attributes: ["id","add_views"],
            });
            console.log('getAdds:::::::::::::::', getAdds)

            //get limit of user steps account
            let limit_step = null ;
            if(!getUser.premium_account){
                if(getAdds){
                    limit_step = await helperService().limitSteps(getAdds.add_views)
                }else{
                    limit_step = 10000
                }
            }else{
                limit_step = 20000
            }
            console.log('limit_step:::::::::::::::', limit_step)

            //get final steps
            let final_steps = null
            if(!usersDailySteps){
                if(limit_step < steps) {
                    final_steps = limit_step //10000
                }else{
                    final_steps = steps
                }
            }else{
                if(limit_step < steps) {
                    final_steps = limit_step -  usersDailySteps.steps   // 6000
                }else{
                    final_steps = steps - usersDailySteps.steps //1006 - 1000 
                }
            
            }
            console.log('final_steps:::::::::::::::', final_steps)
            console.log('getUser.total_steps:::::::::::::::', getUser.total_steps)
            const user_total_steps = parseInt(getUser.total_steps) + parseInt(final_steps)
            console.log('user_total_steps:::::::::::::::', user_total_steps)

            if(!usersDailySteps){
                if(final_steps < 7){
                    let dailySteps = await UsersDailySteps.create({
                        steps: 0,
                        date,
                        user_id,
                    })
                    
                    return helperService().success([], "Steps successful stored ", res);
                }else{
                    await UsersDailySteps.create({
                        steps: final_steps,
                        date,
                        user_id,
                    })
                    await User.update({
                        total_steps: user_total_steps,
                      },
                      {
                        where: {
                          id: user_id
                        }
                      }
                    )
                }
            }else{
                if(final_steps < 7){
                    return helperService().success([], "Steps successful stored ", res);
                }else{
                    if(limit_step < steps){
                        await UsersDailySteps.update({
                            steps: limit_step,
                            date,
                        },{
                            where:{
                                user_id,
                                date
                            }
                        })
                        await User.update({
                            total_steps: user_total_steps,
                          },
                          {
                            where: {
                              id: user_id
                            }
                          }
                        )
                    }else{
                        await UsersDailySteps.update({
                            steps,
                            date,
                        },{
                            where:{
                                user_id,
                                date
                            }
                        })
                        await User.update({
                            total_steps: user_total_steps,
                          },
                          {
                            where: {
                              id: user_id
                            }
                          }
                        )
                    }
                }
            }
            // const tokenomics = await Tokenomics.findAll({
            //     attributes: ["id", "token_supply"]
            // });
            const totalIssuesToken = await TotalIssuesToken.findOne({
                attributes: ["id", "total_supply", "total_issued"]
            });
            if(final_steps >= 7){
                //convert steps to token value
                const getTokenValue = helperService().calculateTokenSuppy(totalIssuesToken.total_supply, totalIssuesToken.total_issued, final_steps)
                // const totalIssuesToken = await TotalIssuesToken.findAll();
                let totalIssuedToken = null

                if(totalIssuesToken){
                    console.log('getTokenValue ::::::::', getTokenValue)
                    console.log('totalIssuedToken ::::::::', totalIssuesToken.total_issued)
                    const tokenIssued = parseFloat(totalIssuesToken.total_issued) + parseFloat(getTokenValue)
                    console.log('tokenIssued ::::::::', tokenIssued)

                    totalIssuedToken = parseFloat(tokenIssued).toFixed(4)
                }
                console.log('totalIssuedToken ::::::::', totalIssuedToken)

                // get user token 
                const userTokens = await UserTokens.findOne({
                    where: {
                        user_id,
                    },
                    attributes: ["id", "total_earned", "current_balance", "onhold"],
                });
                let getTotalEarned = null
                let getCurrentBalance = null
                if(userTokens){
                    getTotalEarned = parseFloat(userTokens.total_earned) + parseFloat(getTokenValue)
                    getTotalEarned = parseFloat(getTotalEarned).toFixed(4)
                    getCurrentBalance = parseFloat(userTokens.current_balance) + parseFloat(getTokenValue)
                    getCurrentBalance = parseFloat(getCurrentBalance).toFixed(4)
                }else{
                    getTotalEarned = getTokenValue
                    getCurrentBalance = getTokenValue
                }
                console.log('+++++++++++++++++++++++++++++++++++++++++++++++++++++++')
                console.log('getTotalEarned:::::::::::::::', getTotalEarned)
                console.log('getCurrentBalance:::::::::::::::', getCurrentBalance)

                const mintHistory = await TokenMintHistory.create({
                    quantity: getTokenValue,
                    date: new Date(),
                    user_id: user_id,
                })
                if(!userTokens){
                    await UserTokens.create({
                        total_earned: getTotalEarned,
                        current_balance: getCurrentBalance,
                        date,
                        user_id,
                    })
                }else{
                    await UserTokens.update({
                        total_earned: getTotalEarned,
                        current_balance: getCurrentBalance,
                    },{
                        where: {
                            user_id,
                        }
                    })
                }
                await TotalIssuesToken.update({
                    total_issued: totalIssuedToken,
                },{
                    where:{
                        id: 2
                    }
                })
                return helperService().success([], "Steps successful stored ", res);
            }
        } catch (err) {
            return helperService().serverError(err, res)
        }
      });
    } else {
      return helperService().badRequest([], "Token is required", res);
    }
};
exports.getStepCount = async (req, res) => {
    const { token, date } = req.query;
    if (token) {
      authService().verify(token, async (err, data) => {
        if (err) {
          return helperService().unauthorized(res);
        }
        try {
            const user_id = data.user_id
            const user = await User.findOne({
                where: {
                    id: user_id,
                },
                attributes: ["id", "name"],
                include: [
                    {
                        model: UsersDailySteps,
                        required: true,
                        attributes: ["id", "date", "steps"],
                        where:{
                            date,
                        }
                    },
                    {
                        model: UserTokens,
                        required: true,
                        attributes: ["id", "total_earned"],
                    },
                ]
            });
            
            return helperService().success(user, "Get steps successful", res);
        } catch (err) {
            return helperService().serverError(err, res)
        }
      });
    } else {
      return helperService().badRequest([], "Token is required", res);
    }
};
exports.updateWallet = async (req, res) => {
    const { token, wallet_address } = req.body,
    message = null,
    foundError = false;
    if (token) {
      authService().verify(token, async (err, data) => {
        if (err) {
          return helperService().unauthorized(res);
        }
        if (wallet_address === null || wallet_address === "") {
            message = "This field is required!!";
            foundError = true;
        }
        if (foundError) {
            return helperService().badRequest([], message, res)
        }
        const user_id = data.user_id
        try {
          const upgrade = await User.update({
                wallet_address
            },
            {
              where: {
                id: user_id
              }
            }
          )
          return helperService().success([], "Wallet address update successfully.", res);
        } catch (err) {
          return helperService().serverError(err, res)
        }
      });
    } else {
      return helperService().badRequest([], "Token is required", res);
    }
}
exports.withdraw = async (req, res) => {
    const { token, amount, withdraw_address } = req.body,
        message = null,
        foundError = false
    const email = process.env.EMAIL_USER
    if (token) {
        authService().verify(token, async (err, data) => {
            if (err) {
                return helperService().unauthorized(res);
            }
            if (amount === null || amount === "") {
                message = "This field is required!";
                foundError = true;
            }
            if (withdraw_address === null || withdraw_address === "") {
                message = "This field is required!";
                foundError = true;
            }
            if (foundError) {
                return helperService().badRequest([], message, res)
            }
            try {
              const user_id = data.user_id
                const user = await User.findByPk(user_id, {
                    include: [
                        {
                            model: UserTokens,
                            required: true,
                            attributes: ["current_balance", "onhold"],
                            raw: true,

                        },
                    ],
                    attributes: ["id", "name"],
                });
                const difference = user.UserTokens[0].current_balance - user.UserTokens[0].onhold // 200 - 10 = 190
                if(difference >= amount){ //190 > 150
                    const addHold = user.UserTokens[0].onhold + amount
                    const createWithdraw = await UserWithdrawals.create({
                        user_id,
                        withdraw_amount: amount,
                        before_withdraw_balance: difference,
                        datetime: new Date(),
                        withdraw_address
                    })
                    const html = `
                        Hello Admin,<br/><br/>
                        ` + user.name + ` has requested to withdraw `+ amount +` of token to this address`+ withdraw_address +`
                        <br/><br/>
                        `+ withdraw_address +`
                        Thanks.`;
                    emailService.sendEmail("withdraw", email, html);
                    await UserTokens.update({
                        onhold: addHold,
                    },{
                        where: {
                            user_id,
                        }
                    })
                    return helperService().success([], "Withdraw request sent successful", res);
                }else{
                    return helperService().success([], "You don't have enough coins", res);
                }
            }catch (err) {
                return helperService().serverError(err, res)
            }
        });
      } else {
        return helperService().badRequest([], "Token is required", res);
      }
};
exports.withdrawGetData = async (req, res) => {
    const { token } = req.query;
    if (token) {
      authService().verify(token, async (err, data) => {
        if (err) {
          return helperService().unauthorized(res);
        }
        try {
            const user_id = data.user_id
            const user = await User.findOne({
                where: {
                    id: user_id,
                },
                attributes: ["id", "mint_address", "wallet_address"],
                include: [
                    {
                        model: UserTokens,
                        required: true,
                        attributes: ["id", "current_balance","onhold"],
                    },
                ]
            });
            
            return helperService().success(user, "success", res);
        } catch (err) {
            return helperService().serverError(err, res)
        }
      });
    } else {
      return helperService().badRequest([], "Token is required", res);
    }
};
exports.transactionHistory = async (req, res) => {
    const { token } = req.query;
    if (token) {
      authService().verify(token, async (err, data) => {
        if (err) {
          return helperService().unauthorized(res);
        }
        try {
            const user_id = data.user_id
            const withdraw = await UserWithdrawals.findAll({
                where: {
                    user_id,
                },
                attributes: ["id", "withdraw_amount", "withdraw_address", "before_withdraw_balance", "datetime", "status"]
            });
            if(withdraw === null){
                return helperService().success([], "No data found", res);
            }else{
                return helperService().success({transaction_history: withdraw}, "Data found", res);
            }
        } catch (err) {
            return helperService().serverError(err, res)
        }
      });
    } else {
      return helperService().badRequest([], "Token is required", res);
    }
};
exports.globalStatistics = async (req, res) => {
    const { token, type } = req.query;
    if (token) {
      authService().verify(token, async (err, data) => {
        if (err) {
          return helperService().unauthorized(res);
        }
        try {
            const user_id = data.user_id
            let withdraw = null
            if(type === 'day'){
                withdraw = await TokenMintHistory.findAll({
                    attributes: [ "date", [sequelize.fn('sum', sequelize.col('quantity')), 'total_quantity'] ],
                    // group: [sequelize.fn('date', sequelize.col('date'))],
                    group: "date",
                    // order: [
                    //     ['date', 'ASC'],
                    // ],
                });
            }else if(type === 'week'){
                withdraw = await TokenMintHistory.findAll({
                    attributes: [ 
                     [sequelize.fn('WEEK', sequelize.col('created_at')), 'week'],
                     [sequelize.fn('sum', sequelize.col('quantity')), 'total_quantity'] ],
                    group: [sequelize.fn('WEEK', sequelize.col('created_at'))],
                });
            }else if(type === 'month'){
                withdraw = await TokenMintHistory.findAll({
                    attributes: [ 
                     [sequelize.fn('MONTH', sequelize.col('created_at')), 'month'],
                     [sequelize.fn('sum', sequelize.col('quantity')), 'total_quantity'] ],
                    group: [sequelize.fn('MONTH', sequelize.col('created_at'))]
                });
            }
            if(withdraw === null){
                return helperService().success([], "No data found", res);
            }else{
                return helperService().success(withdraw, "Data found", res);
            }
        } catch (err) {
            return helperService().serverError(err, res)
        }
      });
    } else {
      return helperService().badRequest([], "Token is required", res);
    }
};
exports.topGlobalPlayers = async (req, res) => {
    const { token } = req.query;
    if (token) {
      authService().verify(token, async (err, data) => {
        if (err) {
          return helperService().unauthorized(res);
        }
        try {
            const user_id = data.user_id
            let topPlayers = await User.findAll({
                attributes: [ "id", "name" ],
                include: [{
                    model: UserTokens,
                    required: true,
                    attributes: ["id", "total_earned"],
                }],
                order: [['UserTokens','total_earned', 'desc']],
                where:{
                    account_status: 1,
                    status: 1,
                    is_verify: 1
                },
                limit: 25
            });
            if(topPlayers === null){
                return helperService().success([], "No data found", res);
            }else{
                return helperService().success(topPlayers, "Data found", res);
            }
        } catch (err) {
            return helperService().serverError(err, res)
        }
      });
    } else {
      return helperService().badRequest([], "Token is required", res);
    }
};