/* eslint-disable no-unused-vars */
const User = require('../models/User')
const Lottery = require('../models/Lottery')
const SurveyCheck = require('../models/SurveyCheck')
const Survey = require('../models/Survey')
const Announcement = require('../models/Announcement')
const { saveUserToArpa, updateUserOnArpa } = require('../ArpaWebservice')
const { generateRandomDigitsInRangeOf } = require('./controllersHelperFunctions')
const { SMS } = require('./SMS_Module')
const { phrases } = require('./SMS_Phrases')

/// /////// times
const minute = 1000 * 60
const hour = minute * 60
const day = hour * 24

/// /////// jobs
const jobs = {
  checkUserActivation() {
    console.log('✅ --job: check users for activation is running')

    return setInterval(async () => {
      try {
        const users = await User.find({ confirmed: false })
        for await (const user of users) {
          // item time and timeout
          const itemTime = Date.parse(user.created_at)
          const timeout = itemTime + day

          // check if passed 24 hours and remove registration
          if (Date.now() >= timeout) {
            await user.remove()
          }
        }
      } catch (e) {
        console.log(e)
      }
    }, hour)
  },
  checkIfAnnouncementsExpired() {
    console.log('✅ --job: check announcements for expire date is running')

    return setInterval(async () => {
      try {
        const announcements = await Announcement.find({ expired: false })
        for await (const notif of announcements) {
          if (Date.now() > notif.expireDate) {
            notif.expired = true
            await notif.save()
          }
        }
      } catch (e) {
        console.log(e)
      }
    }, hour)
  },
  drawLottery() {
    console.log('✅ --job: check for lottery draw is running')

    return setInterval(async () => {
      try {
        const lottery = await Lottery.findOne({ expired: false })
        if (!lottery || lottery.expireDate > Date.now()) return

        /// ///////// assets (arrays)
        const winnersCount = lottery.winnersCount

        const participants = lottery.participants
        const participantsMobileNumbers = []

        const winnersArray = []
        const winnersMobileNumbers = []

        /// ///////// assets (functions)
        function getWinner(array) {
          return new Promise(async (resolve, reject) => {
            const winner = array[generateRandomDigitsInRangeOf(array.length - 1)]
            if (await winnersMobileNumbers.includes(winner.mobile)) resolve(await getWinner(array))
            else {
              winnersMobileNumbers.push(winner.mobile)
              winnersArray.push(winner)
              resolve()
            }
          })
        }

        // normalize repeated mobile numbers to decide which method to use
        for await (const item of participants) {
          if (!participantsMobileNumbers.includes(item.mobile)) participantsMobileNumbers.push(item.mobile)
        }

        // draw function
        if (participantsMobileNumbers.length > 1000) {
          // console.log('------------------------- larg number block ran')

          // chunk all participants to n part (Number(winnersCount) part)
          const partLength = Math.floor(participants.length / winnersCount)
          const chunckedArrayToParts = []

          for (let i = 0; i < winnersCount; i++) {
            const chunck = await participants.slice(i * partLength, i * partLength + partLength)
            await chunckedArrayToParts.push(chunck)
          }

          for await (const item of chunckedArrayToParts) {
            await getWinner(item)
          }
        } else if (participantsMobileNumbers.length > winnersCount) {
          // console.log('------------------------- grater than winnersCount block ran')

          const winnersCountArray = []
          for (let i = 0; i < winnersCount; i++) {
            winnersCountArray.push(i)
          }

          for await (const item of winnersCountArray) {
            await getWinner(participants)
          }
        } else {
          // console.log('------------------------- less or equal to winnersCount block ran')
          for await (const item of participants) {
            if (!winnersMobileNumbers.includes(item.mobile)) {
              winnersMobileNumbers.push(item.mobile)
              winnersArray.push(item)
            }
          }
        }

        // save result to db
        lottery.winnersList = winnersArray
        lottery.markModified('winnersList')
        lottery.expired = true
        lottery.save()

        // send sms for winners
        for await (const item of winnersArray) {
          const msg = [
            'تبریک!!!',
            '\n',
            item.fullName,
            ' عزیز شما در قرعه کشی آسان سرویس با کد پیگیری ',
            item.enrollCode,
            ' برنده شدید. به زودی از شرکت آسان سرویس با شما تماس گرفته خواهد شد. در صورتی که تا 3 روز کاری با شما تماس گرفته نشد میتوانید از طریق شماره 02167341 داخلی 200 و کد پیگیری خود جهت دریافت جایزه اقدام نماید.',
            '\n',
            phrases.thanks,
            '\n',
            phrases.signature
          ]

          SMS([item.mobile], msg.join(''))
        }

        /// /////////////////////////////////////////////////////// fake data for tests

        // for (let i = 0; i < 4; i++) {
        // 	participants.push({
        // 		fullName: 'Amir Mohamadi 2',
        // 		mobile: '34dfssdkfisjdf34534',
        // 		serial: `S-ffasdfdf`,
        // 		enrollCode: `CODE-${i}`
        // 	})
        // 	console.log('--',i)
        // }

        // lottery.participants = []

        // lottery.markModified('participants')
        // return lottery.save()
      } catch (e) {
        console.log('an error happend in drawLottery job --- error: ', e)
      }
    }, hour)
  },
  checkUserSurveys() {
    console.log('✅ --job: check users for surveys is running')

    return setInterval(async () => {
      try {
        const surveyCheck = await SurveyCheck.find({ smsSent: false }).populate('user')
        for await (const item of surveyCheck) {
          // timeout
          const timeout = item.timeAdded + day * 7

          // check if passed one week
          if (Date.now() >= timeout) {
            const survey = await Survey.findOne({ code: item.code })
            if (!survey?._id) {
              const msg = [
                'مشتری گرامی',
                item.user.first_name + ' ' + item.user.last_name,
                '\n',
                'لطفا با شرکت در نظرسنجی خدمات پس از فروش آسان سرویس، میزان رضایت خود از خدمات گارانتی را به ما اعلام کنید و ما را در ارائه خدمات بهتر یاری نمایید. به پاس همراهی شما عزیزان، بین شرکت کنندگان در نظرسنجی ابتدای هرماه به قید قرعه جوایزی اهدا خواهد شد.',
                '\n',
                'لینک شرکت در نظر سنجی:',
                '\n',
                `https://asan-service.com/account/survey?code=${item.code}`
              ]
              SMS([item.user.mobile_number], msg.join(' '))
              item.smsSent = true
              await item.save()
            }
          }
        }
      } catch (e) {
        console.log(e)
      }
    }, day)
  }
}

/// /////// for develop usages
const permissions = require('./permissions')
const devTools = {
  async checkUsersArpaAccounts() {
    try {
      const users = await User.find({ scope: ['user'], confirmed: true })
      let index = 0
      for await (const user of users) {
        if (user.scope.includes('user')) {
          // if (!user.panatech_businessID && !user.panatech_businessCode) {
          // const panatechID = await saveUserToArpa(user, 'panatech')
          // user.panatech_businessID = panatechID.businessID
          // user.panatech_businessCode = panatechID.businessCode
          // await user.save()
          // 	console.log('🚀 ~ file: cronJobs.js ~  panatechID.businessCode', index)
          // }

          index++
        }
      }
    } catch (e) {
      console.log('we got error --- ', e)
    }
  },
  async addNewPermissionsToPrivateAdmin() {
    console.log('addNewPermissionsToPrivateAdmin started')

    try {
      const users = await User.find({ private: true })

      for await (const user of users) {
        // console.log('🚀 ~ file: cronJobs.js ~ line 187 ~ forawait ~ user', user)
        user.permissions = []
        for await (const permission of permissions) {
          user.permissions.push(permission.value)
          // console.log('🚀 ~ file: cronJobs.js ~ line 190 ~ forawait ~ permission', permission.value)
        }
        await user.save()
      }
    } catch (e) {
      console.log(e)
    }
  },
  async findDuplicatedUsers() {
    try {
      const usersArray = new Set()
      const duplicatedUsersArray = new Set()

      const users = await User.find({ scope: ['user'] })

      for await (const user of users) {
        if (!usersArray.has(user.mobile_number)) usersArray.add(user.mobile_number)
        else duplicatedUsersArray.add(user.mobile_number)
      }
      console.log(
        '🚀 ~ file: cronJobs.js ~ line 220 ~ findDuplicatedUsers ~ duplicatedUsersArray',
        duplicatedUsersArray
      )
      console.log(
        '🚀 ~ file: cronJobs.js ~ line 220 ~ findDuplicatedUsers ~ duplicatedUsersArray',
        duplicatedUsersArray.size
      )
    } catch (e) {
      console.log('🚀 ~ file: cronJobs.js ~ line 223 ~ findDuplicatedUsers - catch ~ e', e)
    }
  }
}

module.exports = () => {
  jobs.checkUserActivation()
  jobs.drawLottery()
  jobs.checkIfAnnouncementsExpired()
  jobs.checkUserSurveys()

  // remember to run it once !!!
  // devTools.checkUsersArpaAccounts()
  // devTools.addNewPermissionsToPrivateAdmin()
  // devTools.findDuplicatedUsers()
}
