const Product = require('../models/product/Product')
const {body, validationResult} = require('express-validator')
const dateformat = require('dateformat')
const jimp = require('jimp')
const fs = require('fs')
const v_m = require('../validation_messages')

// local variables
const shortDescriptionLength = 150

const coverWidth = 1010
const coverHeight = 534
const coverQuality = 100

const thumbWidth = 360
const thumbHeight = 294
const thumbQuality = 70

const moreSectionWidth = 778
const moreSectionHeight = 395
const moreSectionQuality = 70

const renderImageWidth = 300
const renderImageHeight = 300
const renderImageQuality = 70

const chartImageQuality = 100

////////////////////////////////////////// products controllers
module.exports.createProduct = [
  [
    body('fa_name')
       .notEmpty().withMessage(v_m['fa'].required.title)
       .bail()
       .custom((value, {req}) => {
         return Product.findOne({'product_details.fa.name': value})
            .then(product => {
              if (product) return Promise.reject(v_m['fa'].duplicated.name)
              else return true
            })
       }),

    body('en_name')
       .notEmpty().withMessage(v_m['fa'].required.title)
       .bail()
       .custom((value, {req}) => {
         return Product.findOne({'product_details.en.name': value})
            .then(product => {
              if (product) return Promise.reject(v_m['fa'].duplicated.name)
              else return true
            })
       }),

    body('fa_short_description')
       .notEmpty().withMessage(v_m['fa'].required.caption),

    body('en_short_description')
       .notEmpty().withMessage(v_m['fa'].required.caption),

    body('fa_page_title')
       .notEmpty().withMessage(v_m['fa'].required.title),

    body('en_page_title')
       .notEmpty().withMessage(v_m['fa'].required.title),

    body('fa_page_description')
       .notEmpty().withMessage(v_m['fa'].required.caption),

    body('en_page_description')
       .notEmpty().withMessage(v_m['fa'].required.caption),

    body('en_page_description')
       .notEmpty().withMessage(v_m['fa'].required.caption),

    body('category')
       .notEmpty().withMessage(v_m['fa'].required.category)
  ],
  async (req, res) => {
    const errors = validationResult(req)
    if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
    if (!req.files || !req.files.cover) return res.status(422).json({validation: {cover: {msg: v_m['fa'].required.cover}}})


    let cover = 'product_' + Date.now() + '.' + req.files.cover.mimetype.split('/')[1]
    let thumb = 'thumb_' + cover
    let more_section_image1 = null
    let more_section_image2 = null
    let render_image1 = null
    let render_image2 = null
    let chart_image = null

    //// generate files names
    if (req.files) {
      if (req.files.more_section_image1) {
        more_section_image1 = 'product_' + Date.now() + 1 + '.' + req.files.more_section_image1.mimetype.split('/')[1]
      }
      if (req.files.more_section_image2) {
        more_section_image2 = 'product_' + Date.now() + 2 + '.' + req.files.more_section_image2.mimetype.split('/')[1]
      }
      if (req.files.render_image1) {
        render_image1 = 'product_' + Date.now() + 3 + '.' + req.files.render_image1.mimetype.split('/')[1]
      }
      if (req.files.render_image2) {
        render_image2 = 'product_' + Date.now() + 4 + '.' + req.files.render_image2.mimetype.split('/')[1]
      }
      if (req.files.chart_image) {
        chart_image = 'product_' + Date.now() + 5 + '.' + req.files.chart_image.mimetype.split('/')[1]
      }
    }


    const data = {
      cover: cover,
      thumb: thumb,
      category: req.body.category,
      more_section: req.body.more_section,
      download_section: req.body.download_section,
      favorite: req.body.favorite,
      product_details: {
        fa: {
          name: req.body.fa_name,
          short_description: req.body.fa_short_description.slice(0, shortDescriptionLength) + ' ... ',
          page_title: req.body.fa_page_title,
          page_description: req.body.fa_page_description,
          more_title1: req.body.fa_more_title1,
          more_description1: req.body.fa_more_description1,
          more_title2: req.body.fa_more_title2,
          more_description2: req.body.fa_more_description2,
          render_caption1: req.body.fa_render_caption1,
          render_caption2: req.body.fa_render_caption2,
          chart_title: req.body.fa_chart_title,
          chart_description: req.body.fa_chart_description
        },
        en: {
          name: req.body.en_name,
          short_description: req.body.en_short_description.slice(0, shortDescriptionLength) + ' ... ',
          page_title: req.body.en_page_title,
          page_description: req.body.en_page_description,
          more_title1: req.body.en_more_title1,
          more_description1: req.body.en_more_description1,
          more_title2: req.body.en_more_title2,
          more_description2: req.body.en_more_description2,
          render_caption1: req.body.en_render_caption1,
          render_caption2: req.body.en_render_caption2,
          chart_title: req.body.en_chart_title,
          chart_description: req.body.en_chart_description
        }
      },
      created_at: dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
    }
    if (req.files.more_section_image1) data.more_section_image1 = more_section_image1
    if (req.files.more_section_image2) data.more_section_image2 = more_section_image2
    if (req.files.render_image1) data.render_image1 = render_image1
    if (req.files.render_image2) data.render_image2 = render_image2
    if (req.files.chart_image) data.chart_image = chart_image

    //// save images
    if (req.files) {
      if (req.files.cover) {
        await jimp.read(req.files.cover.data)
           .then(img => {
             img
                .cover(coverWidth, coverHeight)
                .quality(coverQuality)
                .write(`./static/uploads/images/products/${cover}`)
                .resize(thumbWidth, jimp.AUTO)
                .cover(thumbWidth, thumbHeight)
                .quality(thumbQuality)
                .write(`./static/uploads/images/products/${thumb}`)
           })
           .catch(err => {
             console.log(err)
           })
      }
      if (req.files.more_section_image1) {
        await jimp.read(req.files.more_section_image1.data)
           .then(img => {
             img
                .resize(moreSectionWidth, jimp.AUTO)
                .cover(moreSectionWidth, moreSectionHeight)
                .quality(moreSectionQuality)
                .write(`./static/uploads/images/products/${more_section_image1}`)
           })
           .catch(err => {
             console.log(err)
           })
      }
      if (req.files.more_section_image2) {
        await jimp.read(req.files.more_section_image2.data)
           .then(img => {
             img
                .resize(moreSectionWidth, jimp.AUTO)
                .cover(moreSectionWidth, moreSectionHeight)
                .quality(moreSectionQuality)
                .write(`./static/uploads/images/products/${more_section_image2}`)
           })
           .catch(err => {
             console.log(err)
           })
      }
      if (req.files.render_image1) {
        await jimp.read(req.files.render_image1.data)
           .then(img => {
             img
                .resize(renderImageWidth, jimp.AUTO)
                .cover(renderImageWidth, renderImageHeight)
                .quality(renderImageQuality)
                .write(`./static/uploads/images/products/${render_image1}`)
           })
           .catch(err => {
             console.log(err)
           })
      }
      if (req.files.render_image2) {
        await jimp.read(req.files.render_image2.data)
           .then(img => {
             img
                .resize(renderImageWidth, jimp.AUTO)
                .cover(renderImageWidth, renderImageHeight)
                .quality(renderImageQuality)
                .write(`./static/uploads/images/products/${render_image2}`)
           })
           .catch(err => {
             console.log(err)
           })
      }
      if (req.files.chart_image) {
        await jimp.read(req.files.chart_image.data)
           .then(img => {
             img
                .quality(chartImageQuality)
                .write(`./static/uploads/images/products/${chart_image}`)
           })
           .catch(err => {
             console.log(err)
           })
      }
    }

    //// write to database
    const product = new Product(data)
    product.save((err, data) => {
      if (err) console.log(err)
      return res.json(data)
    })
  }
]

module.exports.getFavoriteProducts = [
  (req, res) => {
    Product.find({favorite: true})
       .select('thumb category product_details')
       .exec((err, products) => {
         if (err) console.log(err)
         return res.json(products)
       })
  }
]

module.exports.getAllProducts = [
  (req, res) => {
    Product.find({}).select('thumb category product_details favorite').exec((err, products) => {
      if (err) console.log(err)
      return res.json(products)
    })
  }
]

module.exports.getOneProduct = [
  (req, res) => {
    Product.findById(req.params.id, (err, product) => {
      if (err) return res.status(404).json({message: err})
      return res.json(product)
    })
  }
]

module.exports.updateProduct = [
  [
    body('fa_name')
       .notEmpty().withMessage(v_m['fa'].required.title)
       .bail()
       .custom((value, {req}) => {
         return Product.findOne({'product_details.fa.name': value})
            .then(product => {
              if (product && product._id.toString() !== req.params.id) return Promise.reject(v_m['fa'].duplicated.name)
              else return true
            })
       }),

    body('en_name')
       .notEmpty().withMessage(v_m['fa'].required.title)
       .bail()
       .custom((value, {req}) => {
         return Product.findOne({'product_details.en.name': value})
            .then(product => {
              if (product && product._id.toString() !== req.params.id) return Promise.reject(v_m['fa'].duplicated.name)
              else return true
            })
       }),

    body('fa_short_description')
       .notEmpty().withMessage(v_m['fa'].required.caption),

    body('en_short_description')
       .notEmpty().withMessage(v_m['fa'].required.caption),

    body('fa_page_title')
       .notEmpty().withMessage(v_m['fa'].required.title),

    body('en_page_title')
       .notEmpty().withMessage(v_m['fa'].required.title),

    body('fa_page_description')
       .notEmpty().withMessage(v_m['fa'].required.caption),

    body('en_page_description')
       .notEmpty().withMessage(v_m['fa'].required.caption),

    body('en_page_description')
       .notEmpty().withMessage(v_m['fa'].required.caption),

    body('category')
       .notEmpty().withMessage(v_m['fa'].required.category)
  ],
  async (req, res) => {
    const errors = validationResult(req)
    if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})

    let cover = null
    let more_section_image1 = null
    let more_section_image2 = null
    let render_image1 = null
    let render_image2 = null
    let chart_image = null

    //// generate files names
    if (req.files) {
      if (req.files.cover) {
        cover = 'product_' + Date.now() + '.' + req.files.cover.mimetype.split('/')[1]
        thumb = 'thumb_' + cover
      }
      if (req.files.more_section_image1) {
        more_section_image1 = 'product_' + Date.now() + 1 + '.' + req.files.more_section_image1.mimetype.split('/')[1]
      }
      if (req.files.more_section_image2) {
        more_section_image2 = 'product_' + Date.now() + 2 + '.' + req.files.more_section_image2.mimetype.split('/')[1]
      }
      if (req.files.render_image1) {
        render_image1 = 'product_' + Date.now() + 3 + '.' + req.files.render_image1.mimetype.split('/')[1]
      }
      if (req.files.render_image2) {
        render_image2 = 'product_' + Date.now() + 4 + '.' + req.files.render_image2.mimetype.split('/')[1]
      }
      if (req.files.chart_image) {
        chart_image = 'product_' + Date.now() + 5 + '.' + req.files.chart_image.mimetype.split('/')[1]
      }
    }


    const data = {
      category: req.body.category,
      more_section: req.body.more_section,
      download_section: req.body.download_section,
      favorite: req.body.favorite,
      product_details: {
        fa: {
          name: req.body.fa_name,
          short_description: req.body.fa_short_description.slice(0, shortDescriptionLength) + ' ... ',
          page_title: req.body.fa_page_title,
          page_description: req.body.fa_page_description,
          more_title1: req.body.fa_more_title1,
          more_description1: req.body.fa_more_description1,
          more_title2: req.body.fa_more_title2,
          more_description2: req.body.fa_more_description2,
          render_caption1: req.body.fa_render_caption1,
          render_caption2: req.body.fa_render_caption2,
          chart_title: req.body.fa_chart_title,
          chart_description: req.body.fa_chart_description
        },
        en: {
          name: req.body.en_name,
          short_description: req.body.en_short_description.slice(0, shortDescriptionLength) + ' ... ',
          page_title: req.body.en_page_title,
          page_description: req.body.en_page_description,
          more_title1: req.body.en_more_title1,
          more_description1: req.body.en_more_description1,
          more_title2: req.body.en_more_title2,
          more_description2: req.body.en_more_description2,
          render_caption1: req.body.en_render_caption1,
          render_caption2: req.body.en_render_caption2,
          chart_title: req.body.en_chart_title,
          chart_description: req.body.en_chart_description
        }
      },
      updated_at: dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
    }

    //// save images
    if (req.files) {
      if (req.files.cover) {
        data.cover = cover
        data.thumb = thumb
        await jimp.read(req.files.cover.data)
           .then(img => {
             img
                .cover(coverWidth, coverHeight)
                .quality(coverQuality)
                .write(`./static/uploads/images/products/${cover}`)
                .resize(thumbWidth, jimp.AUTO)
                .cover(thumbWidth, thumbHeight)
                .quality(thumbQuality)
                .write(`./static/uploads/images/products/${thumb}`)
           })
           .catch(err => {
             console.log(err)
           })
      }

      if (req.files.more_section_image1) {
        data.more_section_image1 = more_section_image1
        await jimp.read(req.files.more_section_image1.data)
           .then(img => {
             img
                .resize(moreSectionWidth, jimp.AUTO)
                .cover(moreSectionWidth, moreSectionHeight)
                .quality(moreSectionQuality)
                .write(`./static/uploads/images/products/${more_section_image1}`)
           })
           .catch(err => {
             console.log(err)
           })
      }

      if (req.files.more_section_image2) {
        data.more_section_image2 = more_section_image2
        await jimp.read(req.files.more_section_image2.data)
           .then(img => {
             img
                .resize(moreSectionWidth, jimp.AUTO)
                .cover(moreSectionWidth, moreSectionHeight)
                .quality(moreSectionQuality)
                .write(`./static/uploads/images/products/${more_section_image2}`)
           })
           .catch(err => {
             console.log(err)
           })
      }

      if (req.files.render_image1) {
        data.render_image1 = render_image1
        await jimp.read(req.files.render_image1.data)
           .then(img => {
             img
                .resize(renderImageWidth, jimp.AUTO)
                .cover(renderImageWidth, renderImageHeight)
                .quality(renderImageQuality)
                .write(`./static/uploads/images/products/${render_image1}`)
           })
           .catch(err => {
             console.log(err)
           })
      }

      if (req.files.render_image2) {
        data.render_image2 = render_image2
        await jimp.read(req.files.render_image2.data)
           .then(img => {
             img
                .resize(renderImageWidth, jimp.AUTO)
                .cover(renderImageWidth, renderImageHeight)
                .quality(renderImageQuality)
                .write(`./static/uploads/images/products/${render_image2}`)
           })
           .catch(err => {
             console.log(err)
           })
      }

      if (req.files.chart_image) {
        data.chart_image = chart_image
        await jimp.read(req.files.chart_image.data)
           .then(img => {
             img
                .quality(chartImageQuality)
                .write(`./static/uploads/images/products/${chart_image}`)
           })
           .catch(err => {
             console.log(err)
           })
      }
    }

    //// write to database
    Product.findByIdAndUpdate(req.params.id, data, (err, oldData) => {
      if (err) console.log(err)
      if (req.files) {
        if (req.files.cover) {
          fs.unlink(`./static/${oldData.cover}`, err => {
            if (err) console.log(err)
          })
          fs.unlink(`./static/${oldData.thumb}`, err => {
            if (err) console.log(err)
          })
        }
        if (req.files.more_section_image1 && oldData.more_section_image1) fs.unlink(`./static/${oldData.more_section_image1}`, err => {
          if (err) console.log(err)
        })
        if (req.files.more_section_image2 && oldData.more_section_image2) fs.unlink(`./static/${oldData.more_section_image2}`, err => {
          if (err) console.log(err)
        })
        if (req.files.render_image1 && oldData.render_image1) fs.unlink(`./static/${oldData.render_image1}`, err => {
          if (err) console.log(err)
        })
        if (req.files.render_image2 && oldData.render_image2) fs.unlink(`./static/${oldData.render_image2}`, err => {
          if (err) console.log(err)
        })
        if (req.files.chart_image && oldData.chart_image) fs.unlink(`./static/${oldData.chart_image}`, err => {
          if (err) console.log(err)
        })
      }
      Product.findById(oldData._id, (err, data) => {
        if (err) console.log(err)
        return res.json(data)
      })
    })
  }
]

module.exports.deleteProduct = [
  (req, res) => {
    Product.findByIdAndDelete(req.params.id, (err, product) => {
      if (err) console.log(err)

      fs.unlink(`./static/${product.cover}`, err => {
        if (err) console.log(err)
      })
      fs.unlink(`./static/${product.thumb}`, err => {
        if (err) console.log(err)
      })

      if (product.more_section_image1) fs.unlink(`./static/${product.more_section_image1}`, err => {
        if (err) console.log(err)
      })
      if (product.more_section_image2) fs.unlink(`./static/${product.more_section_image2}`, err => {
        if (err) console.log(err)
      })
      if (product.render_image1) fs.unlink(`./static/${product.render_image1}`, err => {
        if (err) console.log(err)
      })
      if (product.render_image2) fs.unlink(`./static/${product.render_image2}`, err => {
        if (err) console.log(err)
      })
      if (product.chart_image) fs.unlink(`./static/${product.chart_image}`, err => {
        if (err) console.log(err)
      })

      if (product.images.length) {
        product.images.forEach(item => {
          fs.unlink(`./static/${item.image}`, err => {
            if (err) console.log(err)
          })
        })
      }

      if (product.pdf_files.length) {
        product.pdf_files.forEach(item => {
          fs.unlink(`./static/${item.file.fa}`, err => {
            if (err) console.log(err)
          })
          fs.unlink(`./static/${item.file.en}`, err => {
            if (err) console.log(err)
          })
        })
      }
      return res.json({message: v_m['fa'].response.success_remove})
    })
  }
]

////////////////////////////////////////// products images controllers
module.exports.createProductImage = [
  [
    body('product_id')
       .custom((value, {req}) => {
         return Product.findById(value)
            .then(product => {
              return true
            })
            .catch(err => {
              return Promise.reject(v_m['fa'].not_found.item_id)
            })
       })
  ],
  (req, res) => {
    const errors = validationResult(req)
    if (!errors.isEmpty()) return res.status(422).json({validation: {images: errors.mapped()}})

    let image
    let imageName
    if (req.files && req.files.image) {
      image = req.files.image
      imageName = 'productImages_' + Date.now() + '.' + image.mimetype.split('/')[1]

      jimp.read(image.data)
         .then(img => {
           img
              .cover(coverWidth, coverHeight)
              .quality(coverQuality)
              .write(`./static/uploads/images/products/${imageName}`)

           //// write to database
           Product.findById(req.body.product_id, (err, product) => {
             if (err) console.log(err)
             product.images.push({
               image: imageName,
               created_at: dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
             })
             product.save()
             return res.json(product)
           })
         })
         .catch(err => {
           console.log(err)
         })

    } else {
      return res.status(422).json({validation: {images: {image: {msg: v_m['fa'].required.image}}}})
    }
  }
]

module.exports.deleteProductImage = [
  (req, res) => {
    Product.findOne({'images._id': req.params.imageID}, (err, product) => {
      if (err) return res.status(404).json(err)
      const productImage = product.images.id(req.params.imageID)
      fs.unlink(`./static/${productImage.image}`, err => {
        if (err) console.log(err)
      })
      productImage.remove()
      product.save(err => {
        if (err) console.log(err)
      })
      return res.json(product)
    })
  }
]

////////////////////////////////////////// products features controllers
module.exports.createPDF = [
  [
    body('fa_pdf')
       .notEmpty().withMessage(v_m['fa'].required.title),
    body('en_pdf')
       .notEmpty().withMessage(v_m['fa'].required.title),

    body('product_id')
       .custom((value, {req}) => {
         return Product.findById(value)
            .then(product => {
              return true
            })
            .catch(err => {
              return Promise.reject(v_m['fa'].not_found.item_id)
            })
       })
  ],
  (req, res) => {
    const errors = validationResult(req)
    if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
    if (!req.files || !req.files.file_fa) return res.status(422).json({validation: {file_fa: {msg: v_m['fa'].required.file}}})
    if (!req.files || !req.files.file_en) return res.status(422).json({validation: {file_en: {msg: v_m['fa'].required.file}}})

    Product.findById(req.body.product_id, (err, product) => {
      if (err) console.log(err)

      let fileFa = 'fa_' + product.product_details.fa.name + Date.now() + '.' + req.files.file_fa.mimetype.split('/')[1]
      let fileEn = 'en_' + product.product_details.en.name + Date.now() + '.' + req.files.file_en.mimetype.split('/')[1]
      req.files.file_fa.mv(`./static/uploads/pdf/${fileFa}`, err => {
        if (err) console.log(err)
      })
      req.files.file_en.mv(`./static/uploads/pdf/${fileEn}`, err => {
        if (err) console.log(err)
      })

      const data = {
        file: {
          fa: fileFa,
          en: fileEn
        },
        pdf_details: {
          fa: {
            name: req.body.fa_pdf
          },
          en: {
            name: req.body.en_pdf
          }
        },
        created_at: dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
      }

      product.pdf_files.push(data)
      product.save()
      return res.json(product)
    })
  }
]

module.exports.deletePDF = [
  (req, res) => {
    Product.findOne({'pdf_files._id': req.params.pdfID}, (err, product) => {
      if (err) return res.status(500).json({message: err})
      let pdf = product.pdf_files.id(req.params.pdfID)
      pdf.remove(cb => {
        fs.unlink(`./static/${pdf.file.fa}`, err => {
          if (err) console.log(err)
        })
        fs.unlink(`./static/${pdf.file.en}`, err => {
          if (err) console.log(err)
        })
      })
      product.save()
      return res.json(product)
    })
  }
]
