"use strict";

const _ = require("lodash");
const moment = require("moment");
const httpStatus = require("http-status");
const controllerHelper = require("../../helpers/controller.helper");
const crypto = require("crypto");
const securityHelper = require("../../helpers/security.helper");
const authService = require("./auth.service");
const userService = require("./user.service");
const marketing = require("../../helpers/hubspot.helper");
const marketingService = require("../events/marketing_list.service");
const eventInscriptionService = require("../events/events_inscriptions.service");
const { RequestContactImportNewList } = require("sib-api-v3-sdk");
moment.locale("es");

////////////////////////////////////////////////////////////////////////////////
// CONSTANTS
////////////////////////////////////////////////////////////////////////////////

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

////////////////////////////////////////////////////////////////////////////////
// PUBLIC METHODS
////////////////////////////////////////////////////////////////////////////////

async function login(req, res, next) {
  try {
    const data = {
      id: req.user.id,
      email: req.user.email,
      phone: req.user.phoneNumber,
      fbuid: req.user.uid,
    };

    const tokens = securityHelper.generateToken(data);

    const response = {
      token: tokens.token,
      refreshToken: tokens.refreshToken,
      user: req.user,
    };

    return controllerHelper.handleResultResponse(response, null, req.params, res, httpStatus.OK);
  } catch (error) {
    return controllerHelper.handleErrorResponse(MODULE_NAME, login.name, error, res);
  }
}

async function loginWithPhone(req, res, next) {
  try {
    const appVersion = req && req.headers && req.headers["accept-version"] ? req.headers["accept-version"] : null;
    console.log("loginWithPhone - appVersion: ", appVersion);

    console.log(req.user);
    const findOptions = {
      phone: req.user.phoneNumber,
      fbuid: req.user.uid,
    };

    //Comprobamos si el usuario ya existe en nuestro sistema
    let _user = await authService.extraMethods.findUserByPhone(req.user.phoneNumber);
    if (_user) {
      _user = _user.toJSON();
      if (appVersion) {
        if (_user.app_version != appVersion) {
          userService._updateLastLoginAndVersionUser(_user.id, appVersion);
          _user.app_version = appVersion;
        }
      }

      const tokenData = {
        id: _user.id,
        email: _user.email,
        phone: _user.phone,
        fbuid: _user.fbuid,
      };
      const tokens = securityHelper.generateToken(tokenData);

      _user.token = tokens.token;

      //Recuperamos el número de tickets para los proximos eventos
      try {
        const result = await eventInscriptionService._getInscriptionsOfNextEventsUser(_user.id);
        console.log("Entradas del usuario", result);
        _user.nextTicketsCount = result;
      } catch (error) {
        console.error(error);
        return controllerHelper.handleErrorResponse(MODULE_NAME, "getInscriptionsOfNextEventsCount", error, res);
      }

      return controllerHelper.handleResultResponse(_user, null, req.params, res, httpStatus.OK);
    } else {
      return controllerHelper.handleResultResponse(null, null, req.params, res, httpStatus.NOT_FOUND);
    }
  } catch (error) {
    console.error(error);
    return controllerHelper.handleErrorResponse(MODULE_NAME, login.name, error, res);
  }
}

async function register(req, res, next) {
  function cleanAdminData(user) {
    let cUser = user;
    delete cUser.lastLogin;
    delete cUser.state;
    delete cUser.createdAt;
    delete cUser.updatedAt;
    return cUser;
  }

  const values = {
    phone: req.body.phone,
    fbuid: req.body.fbuid,
  };

  const appVersion = req && req.headers && req.headers["accept-version"] ? req.headers["accept-version"] : null;
  console.log("register - appVersion: ", appVersion);

  //Comprobamos si el usuario ya existe en nuestro sistema
  console.log("COMPROBAMOS SI EXISTE EN NUESTRO SISTEMA", values.phone);
  let newUser = await authService.extraMethods.findUserByPhone(values.phone);

  const data = {
    //refresh_token: tokens.refreshToken,
    phone: req.body.phone,
    fbuid: req.body.fbuid,
    email: req.body.email,
    name: req.body.name,
    surname: req.body.surname,
    entityId: req.body.entityid,
    accessibility: req.body.accessibility,
    profile: req.body.profile,
    country: req.body.country ? req.body.country : "ES",
    app_version: appVersion,
    lastlogin: moment().utc(),
  };

  if (!newUser) {
    console.log("NO EXISTE");
    try {
      newUser = await authService.extraMethods.createUser(data);
      console.log("CREAMOS EL USUARIO EN NUESTRO SISTEMA", newUser);
    } catch (error) {
      console.error(error);
      return controllerHelper.handleErrorResponse(MODULE_NAME, register.name, error, res);
    }
  } else {
    console.log("EXISTE");
    try {
      const oldUserData = newUser;

      newUser = await authService.extraMethods.updateUser(newUser.id, data);

      try {
        const userDTO = marketingService.userToMarketingDTO(newUser);
        if (await marketing.getMemberByEmail(newUser.email)) {
          marketing.updateMemberByEmail(oldUserData.email, userDTO);
        } else {
          // No mandar a Sendinblue hasta que no se inscriba en un congreso.
        }
      } catch (err) {
        console.error(err);
      }

      console.log("MODIFICAMOS EL USUARIO EN NUESTRO SISTEMA", newUser);
    } catch (error) {
      console.error(error);
      return controllerHelper.handleErrorResponse(MODULE_NAME, register.name, error, res);
    }
  }

  if (newUser) {
    newUser = newUser.toJSON();
    newUser = cleanAdminData(newUser);
    if (appVersion) {
      if (newUser.app_version != appVersion) {
        const result = await userService._updateLastLoginAndVersionUser(newUser.id, appVersion);
        newUser.app_version = appVersion;
      }
    }

    const tokenData = {
      phone: values.phone,
      fbuid: values.fbuid,
      id: newUser.id,
      email: newUser.email,
    };
    const tokens = securityHelper.generateToken(tokenData);

    newUser.token = tokens.token;
    console.log("COMO YA EXISTE CREAMOS EL TOKEN Y LO ASIGNAMOS", newUser);
  }

  return controllerHelper.handleResultResponse(newUser, null, req.params, res, httpStatus.OK);
}

async function regenerateToken(req, res, next) {
  const refreshToken = req.body.token;
  const phone = req.body.phone;
  const email = req.body.email;
  const user = await authService.extraMethods.findUserByRefreshToken(refreshToken);

  console.debug(user, req.body);

  if (user && user.phone === phone && user.email === email) {
    const tokenData = {
      phone: user.phone,
      fbuid: user.fbuid,
      id: user.id,
      email: user.email,
    };

    try {
      const tokens = securityHelper.generateToken(tokenData);
      await authService.extraMethods.updateUserRefreshToken(user.id, tokens.refreshToken);
      const result = { token: tokens.token };
      return controllerHelper.handleResultResponse(result, null, req.params, res, httpStatus.OK);
    } catch (error) {
      return controllerHelper.handleErrorResponse(MODULE_NAME, regenerateToken.name, error, res);
    }
  } else {
    return controllerHelper.handleResultResponse(null, null, req.params, res, httpStatus.UNAUTHORIZED);
  }
}

async function rejectToken(req, res, next) {
  const refreshToken = req.body.refreshToken;
  const user = await authService.extraMethods.findUserByRefreshToken(refreshToken);

  if (user && user.token === refreshToken) {
    try {
      await authService.extraMethods.deleteRefreshToken(refreshToken);
      return controllerHelper.handleResultResponse(null, null, req.params, res, httpStatus.OK);
    } catch (error) {
      return controllerHelper.handleErrorResponse(MODULE_NAME, rejectToken.name, error, res);
    }
  } else {
    return controllerHelper.handleResultResponse(null, null, req.params, res, httpStatus.NOT_FOUND);
  }
}

// Registro por email y por password
async function singup(req, res, next) {
  var newUser = undefined;

  try {
    const data = {
      email: req.body.email,
      name: req.body.name,
      surname: req.body.surname,
      level: 8,
      password: crypto.createHash("sha512").update(req.body.password).digest("hex"),
    };

    newUser = await authService.extraMethods.createUser(data);
  } catch (error) {
    console.error(error);
    return controllerHelper.handleErrorResponse(MODULE_NAME, register.name, error, res);
  }

  if (newUser) {
    newUser = newUser.toJSON();

    const tokenData = {
      phone: undefined,
      fbuid: undefined,
      id: newUser.id,
      email: newUser.email,
    };
    const tokens = securityHelper.generateToken(tokenData);

    newUser.token = tokens.token;
  }

  return controllerHelper.handleResultResponse(newUser, null, req.params, res, httpStatus.OK);
}

function adminVerify(req, res, next) {
  return controllerHelper.handleResultResponse("OK", null, req.params, res, httpStatus.OK);
}

function verify(req, res, next) {
  const params = controllerHelper.extractParamsFromRequest(req, res, {});
  const phone = params.query.phone;
  const email = params.query.email;
  const fbuid = params.query.fbuid;
  const user = req.user;

  if (user && user.phone === phone && user.email === email && user.fbuid === fbuid) {
    return controllerHelper.handleResultResponse(user, null, req.params, res, httpStatus.OK);
  } else {
    return controllerHelper.handleResultResponse(null, null, req.params, res, httpStatus.UNAUTHORIZED);
  }
}

async function getOrCreateUser(req, res, next) {
  const params = controllerHelper.extractParamsFromRequest(req, res, {});
  let dataInscription = res.locals.dataInscription;
  if (!dataInscription)
    return controllerHelper.handleResultResponse(
      "Error getOrCreateUser, prepareDataInscription, recuperateReservationByCode requerida",
      null,
      params,
      res,
      httpStatus.NOT_FOUND
    );

  //Iniciamos el usuario relacionadas con la inscripción.
  let dataUser;

  dataUser = {
    id: req.user ? req.user.id : null,
    phone: req.user ? req.user.phone : null, //((req.body.phone != '+34') ? req.body.phone : null), lo quitamos de momento por la de movistar
    name: req.user ? req.user.name : req.body.name,
    surname: req.user ? req.user.surname : req.body.surname,
    email: req.user ? req.user.email : req.body.email,
    entityId: null,
    entityName: null,
    entityLevel: null,
    userResult: req.user ? req.user : null,
  };

  //Asignamos a los datos del usuario a crear, el id de la entidad a la que pertenece, este caso solo es necesario cuando viene la inscripción por web ya que hay que crear un usuario nuevo
  if (dataInscription.reservation) {
    dataUser.entityId = dataInscription.reservation.entityId;
  }

  //creamos o recuperamos el usuario teniendo en cuenta que pude venir por APP o WEB
  //si viene por web se tendra en cuenta el email y si viene por APP el phone para buscar
  try {

    if (req.user) 
    {
      //MAPEO SALIDA API4
      //Caso API V4 user {}
      if (_.isEmpty(req.user)){
         dataUser = {entityId : dataUser.entityId };
         dataUser.userResult = await userService._getOrCreateUserWEBV4(dataUser, req);        
      }
      //Si viene user relleno viene por APP 
      else dataUser.userResult = await userService._getOrCreateUser(dataUser);
    } //Caso Formulario web página actual
    //CHAPUZA SE PERMITE DAR DE ALTA USUARIOS CON EL MISMO CORREO ELECTRONICO, PERO DISTINTO NOMBRE Y APELLIDO.
    else dataUser.userResult = await userService._getOrCreateUserWEB(dataUser);
    
    console.log('CHAPUZAAAAAAAAAA2>>>', dataUser.userResult);

    if (!dataUser.userResult) {
      // No se ha encontrado
      return controllerHelper.handleResultResponse(
        "No se ha podido crear o encontrar el usuario dado",
        null,
        params,
        res,
        httpStatus.NOT_FOUND
      );
    }
  } catch (error) {
    console.log("error>>>>",error);
    return controllerHelper.handleErrorResponse(MODULE_NAME, "getOrCreateUser", error, res);
  }

  //console.log(">>>>>>>>>>>>>>>>>>>>  getOrCreateUser", dataUser.userResult.user.Entity);
  //Refrescamos datos que nos interesan
  dataUser.id = dataUser.userResult.user.id;                                                 //caso API V4 no recuperamos Entidad, asignamos entityId del parametro dado
  dataUser.entityId = dataUser.userResult.user.Entity ? dataUser.userResult.user.Entity.id : (dataUser.userResult.user.entityId? dataUser.userResult.user.entityId : null);
  dataUser.entityName = dataUser.userResult.user.Entity ? dataUser.userResult.user.Entity.name : "DEFAULT";
  dataUser.entityLevel = dataUser.userResult.user.Entity ? dataUser.userResult.user.Entity.level : null;

  dataUser.email = dataUser.userResult.user ? dataUser.userResult.user.email : null;
  dataUser.phone = dataUser.userResult.user ? dataUser.userResult.user.phone : null; //((req.body.phone != '+34') ? req.body.phone : null), lo quitamos de momento por la de movistar
  dataUser.name = dataUser.userResult.user ? dataUser.userResult.user.name : null;
  dataUser.surname = dataUser.userResult.user ? dataUser.userResult.user.surname : null;
  //Reasignamos a variable de entorno
  res.locals.dataUser = dataUser;
  next();
}

async function deleteUser(req, res, next) {
  const params = controllerHelper.extractParamsFromRequest(req, res, {});
  let dataUser = {
    id: req.body ? req.body.id : null,
    phone: req.body ? req.body.phone : null, //((req.body.phone != '+34') ? req.body.phone : null), lo quitamos de momento por la de movistar
    email: req.body ? req.body.email : null,
  };

  const resultCount = await authService.extraMethods.deleteUser(dataUser.id, dataUser.email, dataUser.phone);
  if (resultCount < 1) {
    // No se ha encontrado
    return controllerHelper.handleResultResponse(
      "No se ha podido encontrar el usuario",
      null,
      params,
      res,
      httpStatus.NOT_FOUND
    );
  }

  // Delete in Sendinblue
  try {
    const userDTO = marketingService.userToMarketingDTO(dataUser);
    marketing.deleteMemberByEmail(userDTO.email);
  } catch (error) {
    console.log(error);
    //return controllerHelper.handleErrorResponse(MODULE_NAME, "deleteUser", error, res);
  }

  return controllerHelper.handleResultResponse(resultCount, resultCount, params, res, httpStatus.OK);
}

module.exports = {
  login,
  loginWithPhone,
  register,
  regenerateToken,
  rejectToken,
  singup,
  adminVerify,
  verify,
  getOrCreateUser,
  deleteUser,
  MODULE_NAME,
};
