const asyncHandler = require("express-async-handler");
const moment = require('moment-timezone');
const { ObjectId } = require('mongodb');
const { SaleDb } = require("../services/saleDb");
const saleDb = new SaleDb();
const { LotDb } = require("../services/lotDb");
const lotDb = new LotDb();
const agenda = require('../services/agenda');
const {Agent} = require('../services/agent');
const agent = new Agent();
const ExcelJS = require('exceljs');

exports.getSaleInfos = asyncHandler(async (req, res, next) => {
	  let url = req.params.url
    agent.getSaleInfos(url)
      .then(data => {
        return res.status(200).json(data);
      })
      .catch(error => {
        console.error(error);
        return res.status(500).send({error: error});
      });
});

exports.prepareSale = asyncHandler(async (req, res, next) => {

  try{
    const id = req.params.id; 
    
    agent.prepareSale(id)
      .then(data => {        
        return res.status(200).json({"message": "Lots created"});
      })
      .catch(error => {
        console.error(error);
        return res.status(500).send({error: error});
      });
  }catch(err){
      console.error(err);
      return res.status(500).send({error: err});
  } 
});

exports.followSale = asyncHandler(async (req, res, next) => {

  try{
    const id = req.params.id; 
    
    agent.followSale(id)
      .then(data => {
        res.status(200).send(data);        
      })
      .catch(error => {
        console.error(error);
        return res.status(500).send({error: error});
      });
  }catch(err){
      console.error(err);
      return res.status(500).send({error: err});
  } 
});


// DB
exports.get = asyncHandler(async (req, res, next) => {

  try{
      const id = req.params.id;      
      let result = await saleDb.get(id);      
      res.status(200).send(result);
  }catch(err){
      console.log(err);
      return res.status(500).send({error: err});
  }
  
});

exports.post = asyncHandler(async (req, res, next) => {

  try{
      // check if double
      let Sale = await saleDb.getByIDPlatform(req.body.idPlatform, req.body.platform);
      if(Sale){
        return res.status(500).send({error: "Sale already exists"});
      }

      let createData = await saleDb.post(req.body);
      console.log(createData.insertedId);

      const NowParis = moment.tz(new Date(),"Europe/Paris")
      
      // Scheduling the Prepare job
      const dateSaleMinus24Hours = moment.tz(req.body.date, "Europe/Paris").subtract(24, 'hours');      
      if(dateSaleMinus24Hours.isAfter(NowParis)){        
        const jobPrepare = agenda.create('prepareSale', { saleId: createData.insertedId });
        jobPrepare.schedule(dateSaleMinus24Hours.toDate());
        await jobPrepare.save();
      }else{ console.log("Sale is less than 24 hours away, no Prepare Job");}

      // Scheduling the Follow job
      const dateSale = moment.tz(req.body.date, "Europe/Paris");
      if(dateSale.isAfter(NowParis)){
        const jobFollow = agenda.create('followSale', { saleId: createData.insertedId });
        jobFollow.schedule(dateSale.toDate());
        await jobFollow.save();
      }else{ console.log("Sale is in the past, no Follow Job");}      
      
      res.status(204).send({"message": "Sale created"});
  }catch(err){
      console.log(err);
      return res.status(500).send({error: err});
  }
  
});

exports.put = asyncHandler(async (req, res, next) => {

    try{
        const id = req.params.id;
        let updatedDocument = { ...req.body };        
        delete updatedDocument._id;
        console.log(updatedDocument);
        let result = await saleDb.put(id, updatedDocument);
        //console.log(result);
        res.status(200).send(result);
    }catch(err){
        console.log(err);
        return res.status(500).send({error: err});
    }
    
});

exports.delete = asyncHandler(async (req, res, next) => {
  try{
      const id = req.params.id;      

      // Remove all lots linked to the sale
      console.log("Deleting lots sale_id: "+id);
      await lotDb.deleteAllLotBySaleId(id);

      // Remove the sale
      await saleDb.remove(id);

      //remove the Jobs
      const JobSale = await agenda.jobs({ 'data.saleId': new ObjectId(id) });
      for (const job of JobSale) {
        await job.remove();
      }
            
      res.status(200).send({"message": "Sale and Lots deleted"});
  }catch(err){
      console.log(err);
      return res.status(500).send({error: err});
  }
  
});

// Fucntions

exports.getAll = asyncHandler(async (req, res, next) => {  
  try{
      let result = await saleDb.getAll();      
      res.status(200).send(result);
  }catch(err){
      console.log(err);
      return res.status(500).send({error: err});
  }
});

exports.getByUrl = asyncHandler(async (req, res, next) => {
  try{
      let url = req.params.url
      url = decodeURIComponent(url);

      let result = await saleDb.getByUrl(url);
      //console.log(result);
      res.status(200).send(result);
  }catch(err){
      console.log(err);
      return res.status(500).send({error: err});
  }
});

exports.postProcessing = asyncHandler(async (req, res, next) => {
  try{
      const id = req.params.id;      
      await saleDb.processStats(id);
      res.status(200).send({"message": "Post Processing done"});
  }catch(err){
      console.log(err);
      return res.status(500).send({error: err});
  }
  
});

exports.SaleStatXsl = asyncHandler(async (req, res, next) => {
  try{
      const id = req.params.id;      

      Sale = await saleDb.get(id);
      if(!Sale){
        console.error("Sale not found");
        return res.status(404).send({error: "Sale not found"});
      }

      Lots = await lotDb.getBySaleId(Sale._id.toString(),Sale.platform);

      const workbook = new ExcelJS.Workbook();
      const worksheet = workbook.addWorksheet('Sale Stats');

      worksheet.columns = [
        { header: 'Lot #', key: 'lotNumber', width: 10 },        
        { header: 'Description', key: 'description', width: 100 },
        { header: 'Auctioned Amount', key: 'auctionedAmount', width: 20 },
        { header: 'Estimate Low', key: 'estimateLow', width: 20 },
        { header: 'Estimate High', key: 'estimateHigh', width: 20 },
        { header: 'Bids', key: 'nbrBids', width: 10 },
        { header: 'Highest Bid', key: 'highestBid', width: 20 },
        { header: 'Duration (in s)', key: 'duration', width: 10 },
        { header: '% Above Low', key: 'percentageAboveUnderLow', width: 20 },
        { header: '% Above High', key: 'percentageAboveUnderHigh', width: 20 }
      ];

      let row = 2;
      for (let lot of Lots) {
        let Row = worksheet.addRow({
          lotNumber: lot.lotNumber,          
          description: lot.description,
          auctionedAmount: lot.auctioned?.amount,
          estimateLow: lot.EstimateLow,
          estimateHigh: lot.EstimateHigh,
          nbrBids: lot.postProcessing?.nbrBids,
          highestBid: lot.postProcessing?.highestBid,
          duration: lot.postProcessing?.duration,
          percentageAboveUnderLow: lot.postProcessing?.percentageAboveUnderLow/100,
          percentageAboveUnderHigh: lot.postProcessing?.percentageAboveUnderHigh/100
        });
        
        Row.getCell('C').numFmt = '€0.00';
        Row.getCell('D').numFmt = '€0.00';
        Row.getCell('E').numFmt = '€0.00';
        Row.getCell('B').numFmt = '€0.00';
        Row.getCell('G').numFmt = '€0.00';

        Row.getCell('I').numFmt = '0%';
        Row.getCell('J').numFmt = '0%';
        
        row++;
      }

      worksheet.addRow({
        lotNumber: 'Total',
        auctionedAmount: Sale.postProcessing?.totalAmount,
        estimateLow: '',
        estimateHigh: '',
        nbrBids: '',
        highestBid: '',
        duration: Sale.postProcessing?.duration,
        percentageAboveUnderLow: '',
        percentageAboveUnderHigh: ''
      });

      // send the Xls File
      res.setHeader(
        "Content-Disposition",
        "attachment; filename=" + "SaleStats.xlsx"
      );
    
      await workbook.xlsx.write(res);
      return res.status(200).end();

    }catch(err){
      console.log(err);
      return res.status(500).send
    }
});