const fs = require('fs')
const jimp = require('jimp')
const { body, validationResult } = require('express-validator')
const moment = require('moment-jalaali')
const Lottery = require('../models/Lottery')
const { serialChecker } = require('../plugins/asanServiceSerialChecker')
const { _sr } = require('../plugins/serverResponses')
const {
  res404,
  res406,
  res500,
  checkValidations,
  removeWhiteSpaces,
  checkMobileNumber,
  normalizeMobileNumber
} = require('../plugins/controllersHelperFunctions')
const { SMS } = require('../plugins/SMS_Module')
const { phrases } = require('../plugins/SMS_Phrases')

///
const _faSr = _sr.fa

// date formaters
function SmsDateFormat(date) {
  return moment(date).format('jYYYY/jMM/jDD')
}

module.exports.addLottery = [
  [
    body('title').notEmpty().withMessage(_faSr.required.title),

    body('winnersCount')
      .notEmpty()
      .withMessage('تعداد برندگان قرعه کشی را مشخص کنید')
      .bail()
      .isNumeric()
      .withMessage(_faSr.format.number)
      .bail()
      .custom((value, { req }) => {
        if (Number(value) < 1) return Promise.reject(new Error('تعداد برندگان نمیتواند کمتر از 1 باشد'))
        else return Promise.resolve()
      }),

    body('expireDate')
      .notEmpty()
      .withMessage('تاریخ پایان قرعه کشی را مشخص کنید')
      .bail()
      .isNumeric()
      .withMessage('فرمت صحیح نیست')
      .bail()
      .custom((value, { req }) => {
        if (Number(value) < Date.now()) return Promise.reject(new Error('نمیتوان تاریخ روز جاری یا قبل تر انتخاب کرد.'))
        else return Promise.resolve()
      })
  ],
  checkValidations(validationResult),
  async (req, res) => {
    const { title, winnersCount, expireDate } = req.body
    const supportedImageFormats = ['png', 'jpg', 'jpeg', 'webp']
    let entryBgImgName, resultBgImgName, entryWidth, entryHeight, resultWidth, resultHeight

    try {
      // check for other open lotteries
      const openLotteries = await Lottery.find({ expired: false })
      if (openLotteries.length) return res406(res, 'تا بسته شدن قرعه کشی قبلی نمیتوان قرعه کشی جدید ثبت کرد')

      // required image validations
      if (!req.files || !req.files.entryBgImg)
        return res.status(422).json({ validation: { entryBgImg: { msg: 'عکس صفحه شرکت در قرعه کشی اجباری است' } } })

      if (!req.files || !req.files.resultBgImg)
        return res.status(422).json({
          validation: {
            resultBgImg: {
              msg: 'عکس صفحه نتایج قرعه کشی اجباری است'
            }
          }
        })

      // save images
      if (req.files) {
        // save entry bg image
        if (req.files.entryBgImg) {
          const image = req.files.entryBgImg

          // validate image format
          if (!supportedImageFormats.includes(image.mimetype.split('/')[1])) {
            return res.status(422).json({ validation: { entryBgImg: { msg: _faSr.format.image } } })
          }

          entryBgImgName = 'lotteryEntryBg_' + Date.now() + '.' + image.mimetype.split('/')[1]
          const jimpImg = await jimp.read(image.data)
          jimpImg.quality(100).write(`./static/uploads/images/lottery/${entryBgImgName}`)
          entryWidth = jimpImg.bitmap.width
          entryHeight = jimpImg.bitmap.height
        }

        // save result bg image
        if (req.files.resultBgImg) {
          const image = req.files.resultBgImg

          // validate image format
          if (!supportedImageFormats.includes(image.mimetype.split('/')[1])) {
            return res.status(422).json({ validation: { resultBgImg: { msg: _faSr.format.image } } })
          }

          resultBgImgName = 'lotteryResultBg_' + Date.now() + '.' + image.mimetype.split('/')[1]
          const jimpImg = await jimp.read(image.data)
          jimpImg.quality(100).write(`./static/uploads/images/lottery/${resultBgImgName}`)
          resultWidth = jimpImg.bitmap.width
          resultHeight = jimpImg.bitmap.height
        }
      }

      const data = {
        title,
        winnersCount,
        expireDate
      }
      if (entryBgImgName) {
        data.entryWidth = entryWidth
        data.entryHeight = entryHeight
        data.entryBgImg = entryBgImgName
      }
      if (resultBgImgName) {
        data.resultWidth = resultWidth
        data.resultHeight = resultHeight
        data.resultBgImg = resultBgImgName
      }
      data.lotteryCode = 'L'.concat(moment(Date.now()).format('jMMMjDDjYYYY').toUpperCase())

      const lottery = new Lottery(data)
      await lottery.save()
      return res.json({ message: _faSr.response.success_save })
    } catch (e) {
      return res500(res, `there is an error here --- ${e}`)
    }
  }
]

module.exports.updateLottery = [
  [
    body('title').notEmpty().withMessage(_faSr.required.title),

    body('winnersCount')
      .notEmpty()
      .withMessage('تعداد برندگان قرعه کشی را مشخص کنید')
      .bail()
      .isNumeric()
      .withMessage(_faSr.format.number)
      .bail()
      .custom((value, { req }) => {
        if (Number(value) < 1) return Promise.reject(new Error('تعداد برندگان نمیتواند کمتر از 1 باشد'))
        else return Promise.resolve()
      }),

    body('expireDate')
      .notEmpty()
      .withMessage('تاریخ پایان قرعه کشی را مشخص کنید')
      .bail()
      .isNumeric()
      .withMessage('فرمت صحیح نیست')
      .bail()
      .custom((value, { req }) => {
        if (Number(value) < Date.now()) return Promise.reject(new Error('نمیتوان تاریخ روز جاری یا قبل تر انتخاب کرد.'))
        else return Promise.resolve()
      })
  ],
  checkValidations(validationResult),
  async (req, res) => {
    const { title, winnersCount, expireDate } = req.body
    const supportedImageFormats = ['png', 'jpg', 'jpeg', 'webp']
    let entryBgImgName, resultBgImgName, entryWidth, entryHeight, resultWidth, resultHeight

    try {
      // check lottery expiration
      const lottery = await Lottery.findById(req.params?.lotteryId)
      if (lottery.expired) return res406(res, 'نمیتوان قرعه کشی بسته شده را ویرایش کرد')

      // save images
      if (req.files) {
        // save entry bg image
        if (req.files.entryBgImg) {
          const image = req.files.entryBgImg

          // validate image format
          if (!supportedImageFormats.includes(image.mimetype.split('/')[1])) {
            return res.status(422).json({ validation: { entryBgImg: { msg: _faSr.format.image } } })
          }

          entryBgImgName = 'lotteryEntryBg_' + Date.now() + '.' + image.mimetype.split('/')[1]
          const jimpImg = await jimp.read(image.data)
          jimpImg.quality(100).write(`./static/uploads/images/lottery/${entryBgImgName}`)
          entryWidth = jimpImg.bitmap.width
          entryHeight = jimpImg.bitmap.height
          lottery.entryBgImg &&
            fs.unlink(`./static/${lottery.entryBgImg}`, err => {
              if (err) console.log(err)
            })
        }

        // save result bg image
        if (req.files.resultBgImg) {
          const image = req.files.resultBgImg

          // validate image format
          if (!supportedImageFormats.includes(image.mimetype.split('/')[1])) {
            return res.status(422).json({ validation: { resultBgImg: { msg: _faSr.format.image } } })
          }

          resultBgImgName = 'lotteryResultBg_' + Date.now() + '.' + image.mimetype.split('/')[1]
          const jimpImg = await jimp.read(image.data)
          jimpImg.quality(100).write(`./static/uploads/images/lottery/${resultBgImgName}`)
          resultWidth = jimpImg.bitmap.width
          resultHeight = jimpImg.bitmap.height
          lottery.resultBgImg &&
            fs.unlink(`./static/${lottery.resultBgImg}`, err => {
              if (err) console.log(err)
            })
        }
      }

      lottery.title = title
      lottery.winnersCount = winnersCount
      lottery.expireDate = expireDate

      if (entryBgImgName) {
        lottery.entryWidth = entryWidth
        lottery.entryHeight = entryHeight
        lottery.entryBgImg = entryBgImgName
      }
      if (resultBgImgName) {
        lottery.resultWidth = resultWidth
        lottery.resultHeight = resultHeight
        lottery.resultBgImg = resultBgImgName
      }
      await lottery.save()
      return res.json({ message: _faSr.response.success_save })
    } catch (e) {
      return res500(res, `there is an error here --- ${e}`)
    }
  }
]

module.exports.getAllLotteries = [
  (req, res) => {
    Lottery.find({})
      .sort({ _id: -1 })
      .exec((err, data) => {
        if (err || !data) return res500(res, err)
        else return res.json(data)
      })
  }
]

module.exports.getOneLottery = [
  (req, res) => {
    Lottery.findById(req.params?.lotteryId, (err, data) => {
      if (err || !data) return res404(err)
      else return res.json(data)
    })
  }
]

module.exports.getLastLottery = [
  (req, res) => {
    Lottery.find({})
      .sort({ _id: -1 })
      .select('-participants -winnersCount')
      .exec((err, data) => {
        if (err || !data?.length) return res404(res, 'هیچ قرعه کشی ای در دسترس نیست')
        else return res.json(data[0])
      })
  }
]

module.exports.enrollParticipant = [
  [
    body('fullName')
      .notEmpty()
      .withMessage(_faSr.required.name)
      .bail()
      .isLength({ min: 4 })
      .withMessage(_faSr.min_char.min4)
      .bail()
      .custom((value, { req }) => {
        if (removeWhiteSpaces(value).length < 4) return Promise.reject(_faSr.min_char.min4)
        if (removeWhiteSpaces(value).match(/^[A-Za-z]+$/g))
          return Promise.reject(new Error('لطفا با حروف فارسی تایپ کنید.'))
        else return true
      }),

    body('mobile')
      .notEmpty()
      .withMessage(_faSr.required.phone_number)
      .bail()
      .custom((value, { req }) => {
        const mobileNStatus = checkMobileNumber(value)
        if (!mobileNStatus) return Promise.reject(_faSr.format.phone_number)
        else return Promise.resolve()
      }),

    body('serial')
      .notEmpty()
      .withMessage('شماره سریال گارانتی را وارد کنید')
      .bail()
      .custom(async (value, { req }) => {
        try {
          const serialStatus = await serialChecker(value)
          if (!serialStatus) return Promise.reject(new Error('شماره سریال معتبر نمیباشد'))
          else return Promise.resolve()
        } catch (e) {
          console.log('error in check serials for enrollLotteryController ---- error message: ', e)
          return Promise.reject(new Error('مشکلی در بررسی شماره سریال پیش آمده'))
        }
      })
  ],
  checkValidations(validationResult),
  async (req, res) => {
    const { fullName, mobile, serial, lotteryId } = req.body
    try {
      const lottery = await Lottery.findById(lotteryId)
      if (!lottery) throw new Error('incorrect lottery id')
      if (lottery.expired) return res404(res, 'مهلت شرکت در قرعه کشی به پایان رسیده')

      for await (const item of lottery.participants) {
        if (item.serial === serial) return res404(res, 'این شماره سریال از قبل توسط شخص دیگری ثبت شده است')
      }

      const enrollCode = lottery.lotteryCode
        .concat(lottery.participants.length)
        .concat((Math.random() * 100).toFixed(0))

      const normalizedMN = normalizeMobileNumber(mobile)

      const data = { fullName, mobile: normalizedMN, serial, enrollCode }
      lottery.participants.push(data)
      lottery.markModified('participants')
      await lottery.save()

      const msg = [
        fullName,
        ' عزیز، اطلاعات شما در تاریخ  ',
        SmsDateFormat(Date.now()),
        ' برای شرکت در قرعه کشی آسان سرویس ثبت گردید. ',
        '\n',
        'کد پیگیری: ',
        enrollCode,
        '\n',
        phrases.signature
      ]
      SMS([normalizedMN], msg.join(''))
      return res.json({ message: 'اطلاعات شما با موفیقت در سیستم ثبت شد. کد پیگیری به تلفن همراه شما ارسال گردید' })
    } catch (e) {
      return res500(res, `there is an error here --- ${e}`)
    }
  }
]

module.exports.deleteLottery = [
  (req, res) => {
    Lottery.findByIdAndDelete(req.params?.lotteryId, (err, oldData) => {
      if (err || !oldData) return res404(res, err)
      fs.unlink(`./static/${oldData.entryBgImg}`, err => {
        if (err) console.log(err)
      })
      fs.unlink(`./static/${oldData.resultBgImg}`, err => {
        if (err) console.log(err)
      })
      return res.json({ message: _faSr.response.success_remove })
    })
  }
]
