"use strict";
const moment = require("moment");
const httpStatus = require("http-status");
const generateControllers = require("../../core/controllers");
const { defaultOptions, buildContext } = require("../../core/controllers");
const QRHelper = require("../../helpers/qr.helper");
const emailHelper = require("../../helpers/mail.helper");
const notificationHelper = require("../../helpers/notification.helpers");
const path = require("path");
const messages = require("../../helpers/messages.json");
const eventService = require("./event.service");
const eventReservationService = require("./events_reservations.service");
const eventInscriptionService = require("./events_inscriptions.service");
const notificationService = require("../notification/notification.service");
const marketingListService = require("./marketing_list.service");
const mailService = require("./mail.service");

const {
  extractParamsFromRequest,
  handleErrorResponse,
  handleResultResponse,
} = require("../../helpers/controller.helper");

//PRUEBA
const SchemaValidator = require("../../middlewares/schemaValidator");
const eventValidation = require("./event.validations");
const Joi = require("joi");
const userService = require("../auth/user.service");

// Module Name
const MODULE_NAME = "[event.controller]";

const controllerOptions = {
  MODULE_NAME,
  findOneCallback: eventInscriptionService._fillInscriptionsColor,
};

function generateMemberInscription(user, inscription, reservation) {
  let memberInscription = null;
  if (user && inscription) {
    memberInscription = {
      marketing_memberId: null,
      email: user.email,
      name: user.name,
      surname: user.surname,
      source: inscription.source,
      event_name: inscription.event ? inscription.event.name : "N/A",
      event_date: inscription.event ? inscription.event.init_date : "N/A",
      reservation_code: reservation ? reservation.reservation_code : null,
      date_inscription: inscription.date,
      code_ticket: inscription.code_ticket,
      id_ticket: inscription.id,
      validated: inscription.validated,
      color: reservation ? reservation.color : null,
      description: (reservation ? reservation.description : "Entrada").toUpperCase(),
      entity: reservation ? reservation.Entity.name : user.entityId,
      userId: user.id,
      qrConfig: null,
      qrCode: null,
    };
  }
  console.log('>>>>>>>generateMemberInscription>>>>>>');
  console.log(memberInscription);
  console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><>>>>>>');  

  return memberInscription;
}

const extraControllers = {
  checkCapacity: async (req, res, next) => {
    const params = extractParamsFromRequest(req, res, {});
    let result = {
      eventId: params.params.id,
      group_size: params.query.group_size ? Number(params.query.group_size) : 1,
      allow: false,
      error: undefined,
    };

    if (!result.eventId) {
      return handleResultResponse(null, null, params, res, httpStatus.BAD_REQUEST);
    }

    if (!result.group_size) {
      return handleResultResponse(null, null, params, res, httpStatus.BAD_REQUEST);
    }

    const Event = await eventService._getEvent(result.eventId);
    try {
      if (!Event) {
        result = Object.assign({}, result, {
          error: "El evento solicitado no existe",
        });
      } else {
        let EventOverflow = null;

        if (Event.overflow_eventId && Event.allow_overflow)
          EventOverflow = await eventService._getEvent(Event.overflow_eventId);

        result = Object.assign({}, result, {
          allow: (Event.sold_out) ? false : Event.assistants - Event.confirmed >= result.group_size,
          assistants: Event.assistants,
          confirmed: Event.confirmed,
          sold_out: Event.sold_out,
          assistants_overflow: EventOverflow ? EventOverflow.assistants : 0,
          confirmed_overflow: EventOverflow ? EventOverflow.confirmed : 0,
          sold_out_overflow: EventOverflow ? EventOverflow.sold_out : 1,
          allow_overflow: EventOverflow ? ((EventOverflow ? EventOverflow.sold_out : 1) ? false : EventOverflow.assistants - EventOverflow.confirmed >= result.group_size ) : false,
        });
      }

      //MAPEO SALIDA API4
      //Tratamos resultado, si hay que remover campos para API4 web
      if (res.locals.v4){
        const arrayFieldsremove = res.locals.v4.removeFields;
        arrayFieldsremove.forEach(campo => {
          if (campo in result) {
              delete result[campo];
          }
        });
      };

      return handleResultResponse(result, null, params, res, result === null ? httpStatus.NOT_FOUND : httpStatus.OK);
    } catch (error) {
      return handleErrorResponse(MODULE_NAME, "allowCapacity", error, res);
    }
  },

  //Funcion que devuelve:
  //1. Todas las inscripciones de un evento, cuando el usuario es administrador
  //2. Todas las inscripciones de un usuario, cuando no nos llega ningun param con id
  getInscriptions: async (req, res, next) => {
    const params = extractParamsFromRequest(req, res, {});
    const eventId = params.params.id;
    const userId = req.user.id;
    var result = null;

    console.log(params, req.user.level);
    if (eventId) {
      try {
        if (req.user.level === 8) result = await eventInscriptionService._getInscriptionByEvent(eventId);
        else result = await eventInscriptionService._getInscriptionByEventAndUser(eventId, userId);

        return handleResultResponse(result, null, params, res, result === null ? httpStatus.NOT_FOUND : httpStatus.OK);
      } catch (error) {
        return handleErrorResponse(MODULE_NAME, "getInscriptions", error, res);
      }
    } else {
      try {
        result = await eventInscriptionService._getInscriptionsUser(userId);
        result = result.map((row) => row.toJSON());
        // Asigno colores a las entradas normales
        result = eventInscriptionService._fillInscriptionsColor(result);
        return handleResultResponse(result, null, params, res, result === null ? httpStatus.NOT_FOUND : httpStatus.OK);
      } catch (error) {
        return handleErrorResponse(MODULE_NAME, "getInscriptions", error, res);
      }
    }
  },

  //Funcion que devuelve:
  //1. Todas las inscripciones online de un evento, cuando el usuario es administrador
  getInscriptionsOnline: async (req, res, next) => {
    const params = extractParamsFromRequest(req, res, {});
    const eventId = params.params.id;
    const userId = req.user.id;
    var result = null;

    if (!eventId) return handleResultResponse("Es necesario el ID del evento", null, params, res, httpStatus.NOT_FOUND);

    try {
      result = await eventInscriptionService._getInscriptionOnlineByEvent(eventId);
      //No se le llamará nunca desde la app, la app trata todas las incripciopnes como normales
      //      else result = await eventInscriptionService._getInscriptionByEventAndUser(eventId, userId);
      return handleResultResponse(result, null, params, res, result === null ? httpStatus.NOT_FOUND : httpStatus.OK);
    } catch (error) {
      return handleErrorResponse(MODULE_NAME, "getInscriptionsOnline", error, res);
    }
  },

  getInscriptionsOfNextEventsCount: async (req, res, next) => {
    const params = extractParamsFromRequest(req, res, {});
    const userId = req.user.id;

    try {
      const result = await eventInscriptionService._getInscriptionsOfNextEventsUser(userId);
      return handleResultResponse({ count: result }, null, params, res, httpStatus.OK);
    } catch (error) {
      return handleErrorResponse(MODULE_NAME, "getInscriptionsOfNextEventsCount", error, res);
    }
  },

  findNextEventsByCountry: (config) => {
    function placesCountrysEventsFirst(rows, countryCode) {
      const countryEvents = [];
      const restEvents = [];

      for (const event of rows) {
        if (event.location.country_code === countryCode) {
          countryEvents.push(event);
        } else {
          restEvents.push(event);
        }
      }
      return countryEvents.concat(restEvents);
    }

    return async (req, res, next) => {
      config = config || {
        scopes: [],
      };

      const params = extractParamsFromRequest(req, res, defaultOptions.params.find);
      try {
        const result = await eventService.fetchAll(params, buildContext(req, config));

        const orderedRows = placesCountrysEventsFirst(result.rows, req.user ? req.user.country : req.deviceCountry);

        console.log(orderedRows);
        return handleResultResponse(orderedRows, result.count, params, res);
      } catch (error) {
        return handleErrorResponse(MODULE_NAME, "findNextEventsByCountry", error, res);
      }
    };
  },

  findPartners: async (req, res, next) => {
    const params = extractParamsFromRequest(req, res, {});
    try {
      const result = await eventReservationService._getPartners(params.params.id);
      return handleResultResponse(result, result.count, params, res, httpStatus.OK);
    } catch (error) {
      return handleErrorResponse(MODULE_NAME, "findPartners", error, res);
    }
  },

  findColleges: async (req, res, next) => {
    const params = extractParamsFromRequest(req, res, {});
    try {
      const result = await eventReservationService._getColleges(params.params.id);
      return handleResultResponse(result, result.count, params, res, httpStatus.OK);
    } catch (error) {
      return handleErrorResponse(MODULE_NAME, "findPartners", error, res);
    }
  },

  validateInscription: async (req, res, next) => {
    const params = extractParamsFromRequest(req, res, {});
    const user = req.user;
    const inscriptionId = params.params.id;

    try {
      let inscription = await eventInscriptionService._getInscriptionById(inscriptionId);
      //console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>>>><Inscripcion a Validar:');
      //console.log(inscription);

      //Si la inscripcion no existe o ya está validada no hago nada
      if (!inscription)
        return handleResultResponse("Inscription no encontrada", null, params, res, httpStatus.NOT_FOUND);
      else if (inscription.validated)
        return handleResultResponse("Inscripción validada", null, params, res, httpStatus.OK);

      //Si la inscripción es lista de espera de una reserva
      if (inscription.reservationId) {
        return handleResultResponse(
          "Inscription a validar viene por reserva hay que implementarlo",
          null,
          params,
          res,
          httpStatus.NOT_FOUND
        );
        //                console.log('Tengo reservation>>>>>>>>>>>>>>>>>>', inscription.reservationId);
        //                NewConfirmed = await eventInscriptionService._getCountInscriptionsWithReservation(EventOrReservationChangeId)
        //                marketingListId = (await eventReservationService._getReservaById(EventOrReservationChangeId)).marketing_list;
        //                if (!await eventReservationService._updateConfirmedReservation(EventOrReservationChangeId, NewConfirmed))
        //                    return handleResultResponse("Error al eliminar inscripción, no puedo cambiar confirmados a la reserva asociada", null, params, res, httpStatus.NOT_FOUND);
      }
      //Si la inscripcion es lista de espera del evento
      else if (inscription.overflowEventId) {
        const OverflowEventId = inscription.overflowEventId;

        if ((await eventInscriptionService._validateInscription(inscription.id, user.id)) > 0) {
          inscription.validated = true;
          console.log(">>>>>>>>>>>>>>>>>>>>>>>>>>>>><Inscripcion validada");
          var NewConfirmedOverflow = await eventInscriptionService._getCountInscriptionsWithOverflowEventId(
            OverflowEventId
          );
          var NewConfirmedEvent = await eventInscriptionService._getCountInscriptionsWithoutReservationAndOverflow(
            inscription.eventId
          );
          var marketingListIdOverflow = (await eventService._getEvent(OverflowEventId)).marketing_list;
          var marketingListIdEvent = (await eventService._getEvent(inscription.eventId)).marketing_list;
          console.log(">>>>>>>>>>>>>>><NewConfirmedOverflow: ", NewConfirmedOverflow);
          console.log(">>>>>>>>>>>>>>><NewConfirmedEvent: ", NewConfirmedEvent);

          //Actualizamos aforos
          if (!(await eventService._updateConfirmedEvent(OverflowEventId, NewConfirmedOverflow)))
            return handleResultResponse(
              "Error al validad inscripción, no puedo cambiar confirmados a la lista de espera",
              null,
              params,
              res,
              httpStatus.NOT_FOUND
            );
          if (!(await eventService._updateConfirmedEvent(inscription.eventId, NewConfirmedEvent)))
            return handleResultResponse(
              "Error al validad inscripción, no puedo cambiar confirmados al evento",
              null,
              params,
              res,
              httpStatus.NOT_FOUND
            );

          if (marketingListIdOverflow) {
            try {
              //Eliminamos miembro de la lista de mailchimp a la que está asociado

              await marketingListService._deleteMember(marketingListIdOverflow, inscription.user.email); // inscription.marketing_memberId);
            } catch (error) {
              console.log("validate incription", error);
            }
          }

          //Mandar correo de confirmacion de inscripcion
          try {
            var member = generateMemberInscription(inscription.user, inscription, inscription.reservation);

            /**** */

            member.marketing_memberId = await eventInscriptionService._addMember(marketingListIdEvent, member);
            eventInscriptionService._updateMarketingMemberOfInscription(inscription.id, member.marketing_memberId);

            /*** */

            member.qrConfig = QRHelper.generateQRConfig(member);
            member.qrCode = await QRHelper.getInscriptionQRCode(member.qrConfig);
            member.qrCodeUrl = QRHelper.getInscriptionQRCodeUrl(inscription.id);
            //console.log("mandar correo>>>>>>>>>>>>>await QRHelper.getInscriptionQRCode(member.qrConfig); >>>>>>>> ",
            //  member
            //);
            emailHelper.sendTicket(mailService.generateHeaderMail(member), mailService.generateBodyMail(member));
          } catch (error) {
            console.log("No se ha podido mandar email con entrada");
          }

          try {
            let notification = notificationHelper.createNotificationValidatedInscription(inscription);
            console.log(notification);
            let result = notificationService.sendNotificationToUsers(notification, [inscription.user.id]);

            console.log(result);
          } catch (error) {
            console.log("No se ha podido mandar push");
          }
        }

        return handleResultResponse("Inscripción validada", null, params, res, httpStatus.OK);
      } else return handleResultResponse("No se pudo validar inscripción", null, params, res, httpStatus.NOT_FOUND);
    } catch (error) {
      console.log(error);
      return handleResultResponse("Error al validar inscripción", null, params, res, httpStatus.NOT_FOUND);
    }
  },

  syncronizeMarketingList: async (req, res, next) => {
    const params = extractParamsFromRequest(req, res, {});
    const user = req.user;
    const eventId = params.params.id;
    console.log(">>>>>>>>>>>>>>>>>>>>>>>>>>>>><syncronizeMarketingList");

    if (marketingListService.syncronizeEventWithMarketingList(eventId))
      return handleResultResponse(
        "La sincronización se ha realizado correctamente",
        null,
        params,
        res,
        httpStatus.DELETEOK
      );
  },

  getQRCodeInscription: async (req, res, next) => {
    const params = extractParamsFromRequest(req, res, {});
    const inscriptionId = params.params.id;
    const userId = req.user.id;

    try {
      const inscription = await eventInscriptionService._getInscriptionById(inscriptionId);
      if (!inscription) {
        return handleResultResponse("Inscription no encontrada", null, params, res, httpStatus.NOT_FOUND);
      } else if (inscription.userId !== userId) {
        return handleResultResponse("Inscription no encontrada", null, params, res, httpStatus.NOT_FOUND);
      }

      //Creamos objeto member para facilitar inserción en mailchimp y envio de correo
      var member = generateMemberInscription(req.user, inscription.inscription, inscription.reservation);
      member.qrConfig = QRHelper.generateQRConfig(member);
      member.qrCode = await QRHelper.getInscriptionQRCode(member.qrConfig);
      member.qrCodeUrl = QRHelper.getInscriptionQRCodeUrl(inscription.id);

      return handleResultResponse(member.qrCode, null, params, res, httpStatus.OK);
    } catch (error) {
      return handleResultResponse("Error al buscar la inscripción", null, params, res, httpStatus.NOT_FOUND);
    }
  },

  sendMailTicket: async (req, res, next) => {
    const params = extractParamsFromRequest(req, res, {});
    const inscriptionId = params.params.id;
    const user = req.user;
    try {
      const inscription = await eventInscriptionService._getInscriptionById(inscriptionId);
      if (!inscription)
        return handleResultResponse("Inscription no encontrada", null, params, res, httpStatus.NOT_FOUND);

      console.log("soy administrador?????? ", user);
      //            if (inscription.userId !== user.id)
      //                return handleResultResponse("Inscription no encontrada", null, params, res, httpStatus.NOT_FOUND);

      const userInscription = await userService._getUserById(inscription.userId);

      //Creamos objeto member para facilitar inserción en mailchimp y envio de correo
      var member = generateMemberInscription(userInscription, inscription, inscription.reservation);
      member.qrConfig = QRHelper.generateQRConfig(member);
      member.qrCode = await QRHelper.getInscriptionQRCode(member.qrConfig);
      member.qrCodeUrl = QRHelper.getInscriptionQRCodeUrl(inscription.id);

      //console.log("Mandamos mail con entrada 2 member>>>>>>>>>>>>>>>>>>>>>>>>>>>");
      //console.log(member);

      try {
        if (member.validated)
          emailHelper.sendTicket(mailService.generateHeaderMail(member), mailService.generateBodyMail(member));
        else emailHelper.sendListaEspera(mailService.generateHeaderMail(member), mailService.generateBodyMail(member));
      } catch (error) {
        console.log("No se ha podido mandar email con entrada");
      }

      return handleResultResponse(null, null, params, res, httpStatus.OK);
    } catch (error) {
      return handleResultResponse("Error al buscar la inscripción", null, params, res, httpStatus.NOT_FOUND);
    }
  },

  getInscripcionsExcel: async (req, res, next) => {
    const params = extractParamsFromRequest(req, res, {});
    const eventId = params.params.id;
    const userId = req.user.id;

    const inscriptions = await eventInscriptionService._getInscriptionsExcel(
      req.user,
      eventId,
      function (result, status) {
        if (result.messenger.code == "S99001") {
          console.log(result);
          res.setHeader("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
          res.setHeader("Content-Disposition", "attachment; filename=" + result.data.name);
          res.attachment(result.data.name);
          res.download(path.resolve(result.data.path), result.data.name);
        } else {
          res.status(status).json(result);
        }
      }
    );
  },

  getQRCodeImage: async (req, res, next) => {
    const params = extractParamsFromRequest(req, res, {});
    const inscriptionId = params.params.id;

    try {
      const inscription = await eventInscriptionService._getInscriptionById(inscriptionId);
      if (!inscription) {
        return handleResultResponse("Inscripcion no encontrada", null, params, res, httpStatus.NOT_FOUND);
      }

      //Creamos objeto member para facilitar inserción en mailchimp y envio de correo
      let member = generateMemberInscription(inscription.user, inscription, inscription.reservation);

      member.qrConfig = QRHelper.generateQRConfig(member);
      member.qrCode = await QRHelper.getInscriptionQRCode(member.qrConfig);

      let buffer = new Buffer.from(member.qrCode.split(",")[1], "base64");

      res.setHeader("Content-Type", "image/png");
      res.setHeader("Content-Length", buffer.length);
      return handleResultResponse(buffer, null, params, res, httpStatus.OK);
    } catch (error) {
      return handleErrorResponse("Error al buscar la inscripción", error, params, res, httpStatus.NOT_FOUND);
    }
  },
};

module.exports = generateControllers(eventService, extraControllers, controllerOptions);
