const moment = require('moment-jalaali')
const { body, validationResult } = require('express-validator')
const TransactionDraft = require('../models/TransactionDraft')
const Transaction = require('../models/Transaction')
const User = require('../models/User')
const SurveyCheck = require('../models/SurveyCheck')
const { _sr } = require('../plugins/serverResponses')
const { saveTransactionToArpa } = require('../ArpaWebservice.js')
const {
  res404,
  res406,
  res500,
  checkValidations,
  generateRandomDigits
} = require('../plugins/controllersHelperFunctions')
const { SMS } = require('../plugins/SMS_Module')
const { phrases } = require('../plugins/SMS_Phrases')
const { notifyAgent } = require('../WebSocket/controllers/agent_EventsController')
const { notifyUser } = require('../WebSocket/controllers/user_EventsController')
const _faSr = _sr.fa

// date formatters
function ArpaDateFormat(date) {
  return moment(date).format('YYYY-MM-DD HH:mm:ss')
}

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

/// ///////////////// users
module.exports.add_transaction = [
  [
    body('BusinessID').notEmpty().withMessage('Enter businessID'),
    body('cAddress1').notEmpty().withMessage(_faSr.required.address),
    body('TransCCustom1').notEmpty().withMessage(_faSr.required.receiver_first_name),
    body('cTel1').notEmpty().withMessage(_faSr.required.receiver_mobile)
  ],
  checkValidations(validationResult),
  async (req, res) => {
    if (!req.body.termsOfUse) return res406(res, 'با متن تعهدنامه موافقت نکرده اید')
    if (!req.body.items?.length) return res406(res, 'هیچ کالایی به فرم اضافه نکرده اید')

    const { BusinessID, Description, cAddress1, TransCCustom1, cTel1, items, draftId, db_name, agent } = req.body

    const data = {
      BusinessID,
      Description,
      cAddress1,
      TransCCustom1,
      cTel1
    }

    try {
      const userId = req.user_id
      const thisTime = Date.now()
      // check user id and agent status
      const user = await User.findById(userId)
      if (!user) return res406(res, 'اطلاعات کاربری صحیح نمیباشد')
      if (user.isAgent && agent !== 'main')
        return res406(res, 'نمایندگان فقط میتوانند به خود شرکت آسان سرویس فرم ارسال نمایند')

      function getMessageTxt(transNumber) {
        const msgArray = [
          'مشتری گرامی',
          user.first_name + ' ' + user.last_name,
          '\n',
          'کالاهای شما با شماره پذیرش موقت',
          transNumber,
          'در سایت آسان سرویس ثبت گردید. کالاهای ارسالی شما پس از دریافت توسط واحد  گارانتی، بررسی شده و به شما اطلاع رسانی خواهد شد.',
          '\n',
          phrases.signature
        ]
        return msgArray.join(' ')
      }
     
      if (agent === 'main') {
        const ArpaResponse = await saveTransactionToArpa(data, items, db_name)
        await TransactionDraft.findByIdAndRemove(draftId)
        SMS([user.mobile_number], getMessageTxt(ArpaResponse))
        notifyUser('updateDraftsCount', userId)
        return res.json({
          host: 'ar',
          transNumber: ArpaResponse
        })
      } else {
        // get transactions count
        const transactions = await Transaction.find()
        // fill specific fields
        data.user_id = userId
        data.agent_id = agent
        data.db_name = db_name
        data.items = items
        data.TempReceiptTransDate = ArpaDateFormat(thisTime)
        data.TempReceiptTransNumber = 'AG' + transactions.length.toString().padStart(4, '0')
        data.statusHistory = [{ status: 'saved', date: thisTime }]
        const transaction = new Transaction(data)
        await transaction.save()
        await TransactionDraft.findByIdAndRemove(draftId)
        SMS([user.mobile_number], getMessageTxt(transaction.TempReceiptTransNumber))
        notifyUser('updateDraftsCount', userId)
        notifyAgent('newAgentInbox', agent)
        notifyAgent('updateAgentInbox', agent)
        return res.json({
          host: 'as',
          transNumber: transaction.TempReceiptTransNumber
        })
      }
    } catch (e) {
      // console.log('there is an error in (Post Transaction to Arpa)', e)
      return res500(res, e)
    }
  }
]

module.exports.get_all_transactions_for_user = [
  (req, res) => {
    const { user_id } = req
    Transaction.find({ user_id }, (err, data) => {
      if (err) return res500(res, err)
      else return res.json(data)
    })
  }
]

module.exports.get_one_transaction_for_user = [
  (req, res) => {
    const { user_id } = req
    Transaction.findOne({ user_id, TempReceiptTransNumber: req.params?.ttn })
      .populate('agent_id', 'full_name province_name city_name address postal_code tel_number mobile_number')
      .exec((err, data) => {
        if (err || !data) return res404(res, err)
        else return res.json(data)
      })
  }
]

/// ///////////////// agents
module.exports.get_all_transactions_for_agent = [
  async (req, res) => {
    try {
      const { agent_id } = req
      const transactions = await Transaction.find({ agent_id }).sort({created_at:-1})
      return res.json(transactions)
    } catch (e) {
      return res500(res, e)
    }
  }
]

module.exports.get_one_transaction_for_agent = [
  async (req, res) => {
    try {
      const { agent_id } = req
      const transaction = await Transaction.findOne({ agent_id, _id: req.params?.id })
      if (!transaction) return res404(res, 'invalid transaction id')
      if (!transaction.seen) {
        transaction.seen = true
        await transaction.save()
        notifyAgent('updateAgentInbox', agent_id)
      }
      return res.json(transaction)
    } catch (e) {
      return res500(res, e)
    }
  }
]

module.exports.change_transaction_status_by_agent = [
  [
    body('status')
      .notEmpty()
      .withMessage('status is required')
      .bail()
      .custom((value, { req }) => {
        const acceptablvalues = ['recieved', 'ongoing', 'waiting', 'delivered']
        if (!acceptablvalues.includes(value)) return Promise.reject(new Error('invalid status'))
        else return true
      })
  ],
  checkValidations(validationResult),
  async (req, res) => {
    const { status, deliveryCode } = req.body
    const { agent_id } = req
    const thisTime = Date.now()

    try {
      const transaction = await Transaction.findOne({ agent_id, _id: req.params?.id })
      if (!transaction) return res404(res, 'invalid transaction id')

      // status order check
      const errMsg = 'invalid status for this time'

      if (transaction.status === 'saved' && status !== 'recieved') return res406(res, errMsg)
      if (transaction.status === 'recieved' && status !== 'ongoing') return res406(res, errMsg)

      // avoid repeated status
      if (transaction.status === 'waiting' && status === 'waiting') return res406(res, errMsg)
      if (transaction.status === 'delivered' && status === 'delivered') return res406(res, errMsg)

      // save status
      transaction.status = status
      transaction.statusHistory.push({ status, date: thisTime })

      let smsMessage
      // different status methods
      if (status === 'recieved') {
        const receiptTN = transaction.TempReceiptTransNumber + 'R' + generateRandomDigits(2)
        transaction.ItemReceptionTransNumber = receiptTN
        transaction.ItemReceptionTransDate = ArpaDateFormat(thisTime)

        smsMessage = [
          ' کاربر گرامی فرم گارانتی شما با کد پذیرش موقت ',
          transaction.TempReceiptTransNumber,
          ' در تاریخ ',
          SmsDateFormat(thisTime),
          ' تحویل دفتر نمایندگی و پذیرش شد. ',
          '\n',
          ' کد پذیرش: ',
          receiptTN,
          '\n',
          phrases.signature
        ]
      }

      if (status === 'ongoing') {
        smsMessage = [
          ' کاربر گرامی فرم گارانتی شما با کد پذیرش ',
          transaction.ItemReceptionTransNumber,
          ' در تاریخ ',
          SmsDateFormat(thisTime),
          ' در دست اقدام قرار گرفت. ',
          '\n',
          phrases.signature
        ]
      }

      if (status === 'waiting') {
        smsMessage = [
          ' کاربر گرامی فرم گارانتی شما با کد پذیرش ',
          transaction.ItemReceptionTransNumber,
          ' در تاریخ ',
          SmsDateFormat(thisTime),
          ' در انتظار قطعه میباشد. ',
          '\n',
          phrases.signature
        ]
      }

      if (status === 'delivered') {
        if (deliveryCode) transaction.deliveryCode = deliveryCode

        function deliveryCodePhrase() {
          if (deliveryCode.length) return `کد پیگیری مرسوله: ${deliveryCode}` + '\n'
          else return ''
        }

        smsMessage = [
          ' کاربر گرامی فرم گارانتی شما با کد پذیرش ',
          transaction.ItemReceptionTransNumber,
          ' در تاریخ ',
          SmsDateFormat(thisTime),
          ' تحویل شد. ',
          '\n',
          deliveryCodePhrase(),
          phrases.signature
        ]

        const surveyData = {
          code: transaction.ItemReceptionTransNumber,
          user: transaction.user_id,
          timeAdded: Date.now()
        }
        const surveyCheck = new SurveyCheck(surveyData)
        surveyCheck.save(err => {
          if (err) console.log('surveyCheck save error', err)
        })
      }

      await SMS([transaction.cTel1], smsMessage.join(''))
      await transaction.save()

      return res.json({ message: _faSr.response.success_save })
    } catch (e) {
      return res500(res, e)
    }
  }
]

/// ///////////////// admin
module.exports.get_all_agents_inbox_for_admin = [
  async (req, res) => {
    try {
      const transactions = await Transaction.find().sort({created_at:-1})
        .populate('agent_id', 'agent_code full_name')
        .populate('user_id', 'province_id province_name city_id city_name')
      return res.json(transactions)
    } catch (e) {
      return res500(res, e)
    }
  }
]

module.exports.get_one_agent_inbox_for_admin = [
  async (req, res) => {
    try {
      const agent_id = req.params?.agent_id
      const transactions = await Transaction.find({ agent_id })
      return res.json(transactions)
    } catch (e) {
      return res500(res, e)
    }
  }
]

module.exports.get_one_transaction_for_admin = [
  (req, res) => {
    Transaction.findById(req.params?.id)
      .populate(
        'agent_id',
        'full_name province_name city_name address postal_code tel_number fax_number mobile_number store_name agent_code'
      )
      .populate(
        'user_id',
        'first_name last_name province_name city_name panatech_businessCode verity_businessCode national_code mobile_number address postal_code'
      )
      .exec((err, data) => {
        if (err || !data) return res404(res, err)
        else return res.json(data)
      })
  }
]
