text: /* eslint-disable  func-names */
  /* eslint-disable  no-restricted-syntax */
  /* eslint-disable  no-loop-func */
  /* eslint-disable  consistent-return */
  /* eslint-disable  no-console */
  /* eslint-disable max-len */
  /* eslint-disable prefer-destructuring */
  
  const Alexa = require('ask-sdk-core');
  const https = require('https');
  
  /* INTENT HANDLERS */
  
  const LaunchRequestHandler = {
    canHandle(handlerInput) {
      return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
    },
    handle(handlerInput) {
      return handlerInput.responseBuilder
        .speak('Welcome to pet match. I can help you find the best dog for you. ' +
          'What are two things you are looking for in a dog?')
        .reprompt('What size and temperament are you looking for in a dog?')
        .getResponse();
    },
  };
  
  const MythicalCreaturesHandler = {
    canHandle(handlerInput) {
      if (handlerInput.requestEnvelope.request.type !== 'IntentRequest'
        || handlerInput.requestEnvelope.request.intent.name !== 'PetMatchIntent') {
        return false;
      }
  
      let isMythicalCreatures = false;
      if (handlerInput.requestEnvelope.request.intent.slots.pet
        && handlerInput.requestEnvelope.request.intent.slots.pet.resolutions
        && handlerInput.requestEnvelope.request.intent.slots.pet.resolutions.resolutionsPerAuthority[0]
        && handlerInput.requestEnvelope.request.intent.slots.pet.resolutions.resolutionsPerAuthority[0].values
        && handlerInput.requestEnvelope.request.intent.slots.pet.resolutions.resolutionsPerAuthority[0].values[0]
        && handlerInput.requestEnvelope.request.intent.slots.pet.resolutions.resolutionsPerAuthority[0].values[0].value
        && handlerInput.requestEnvelope.request.intent.slots.pet.resolutions.resolutionsPerAuthority[0].values[0].value.name === 'mythical_creatures') {
        const attributesManager = handlerInput.attributesManager;
        const sessionAttributes = attributesManager.getSessionAttributes();
        sessionAttributes.mythicalCreature = handlerInput.requestEnvelope.request.intent.slots.pet.value;
        attributesManager.setSessionAttributes(sessionAttributes);
        isMythicalCreatures = true;
      }
  
      return isMythicalCreatures;
    },
    handle(handlerInput) {
      const attributesManager = handlerInput.attributesManager;
      const sessionAttributes = attributesManager.getSessionAttributes();
  
      const outputSpeech = randomPhrase(slotsMeta.pet.invalid_responses).replace('{0}', sessionAttributes.mythicalCreature);
  
      return handlerInput.responseBuilder
        .speak(outputSpeech)
        .getResponse();
    },
  };
  
  const InProgressPetMatchIntent = {
    canHandle(handlerInput) {
      const request = handlerInput.requestEnvelope.request;
  
      return request.type === 'IntentRequest'
        && request.intent.name === 'PetMatchIntent'
        && request.dialogState !== 'COMPLETED';
    },
    handle(handlerInput) {
      const currentIntent = handlerInput.requestEnvelope.request.intent;
      let prompt = '';
  
      for (const slotName in currentIntent.slots) {
        if (Object.prototype.hasOwnProperty.call(currentIntent.slots, slotName)) {
          const currentSlot = currentIntent.slots[slotName];
          if (currentSlot.confirmationStatus !== 'CONFIRMED'
            && currentSlot.resolutions
            && currentSlot.resolutions.resolutionsPerAuthority[0]) {
            if (currentSlot.resolutions.resolutionsPerAuthority[0].status.code === 'ER_SUCCESS_MATCH') {
              if (currentSlot.resolutions.resolutionsPerAuthority[0].values.length > 1) {
                prompt = 'Which would you like';
                const size = currentSlot.resolutions.resolutionsPerAuthority[0].values.length;
  
                currentSlot.resolutions.resolutionsPerAuthority[0].values
                  .forEach((element, index) => {
                    prompt += ` ${(index === size - 1) ? ' or' : ' '} ${element.value.name}`;
                  });
  
                prompt += '?';
  
                return handlerInput.responseBuilder
                  .speak(prompt)
                  .reprompt(prompt)
                  .addElicitSlotDirective(currentSlot.name)
                  .getResponse();
              }
            } else if (currentSlot.resolutions.resolutionsPerAuthority[0].status.code === 'ER_SUCCESS_NO_MATCH') {
              if (requiredSlots.indexOf(currentSlot.name) > -1) {
                prompt = `What ${currentSlot.name} are you looking for`;
  
                return handlerInput.responseBuilder
                  .speak(prompt)
                  .reprompt(prompt)
                  .addElicitSlotDirective(currentSlot.name)
                  .getResponse();
              }
            }
          }
        }
      }
  
      return handlerInput.responseBuilder
        .addDelegateDirective(currentIntent)
        .getResponse();
    },
  };
  
  const CompletedPetMatchIntent = {
    canHandle(handlerInput) {
      const request = handlerInput.requestEnvelope.request;
  
      return request.type === 'IntentRequest'
        && request.intent.name === 'PetMatchIntent'
        && request.dialogState === 'COMPLETED';
    },
    async handle(handlerInput) {
      const filledSlots = handlerInput.requestEnvelope.request.intent.slots;
  
      const slotValues = getSlotValues(filledSlots);
      const petMatchOptions = buildPetMatchOptions(slotValues);
  
      let outputSpeech = '';
  
      try {
        const response = await httpGet(petMatchOptions);
  
        if (response.result.length > 0) {
          outputSpeech = `So a ${slotValues.size.resolved} 
            ${slotValues.temperament.resolved} 
            ${slotValues.energy.resolved} 
            energy dog sounds good for you. Consider a 
            ${response.result[0].breed}`;
        } else {
          outputSpeech = `I am sorry I could not find a match 
            for a ${slotValues.size.resolved} 
            ${slotValues.temperament.resolved} 
            ${slotValues.energy.resolved} dog`;
        }
      } catch (error) {
        outputSpeech = 'I am really sorry. I am unable to access part of my memory. Please try again later';
        console.log(`Intent: ${handlerInput.requestEnvelope.request.intent.name}: message: ${error.message}`);
      }
  
      return handlerInput.responseBuilder
        .speak(outputSpeech)
        .getResponse();
    },
  };
  
  const FallbackHandler = {
    canHandle(handlerInput) {
      return handlerInput.requestEnvelope.request.type === 'IntentRequest'
        && handlerInput.requestEnvelope.request.intent.name === 'AMAZON.FallbackIntent';
    },
    handle(handlerInput) {
      return handlerInput.responseBuilder
        .speak('I\'m sorry Pet Match can\'t help you with that. ' +
          'I can help find the perfect dog for you. What are two things you\'re ' +
          'looking for in a dog?')
        .reprompt('What size and temperament are you looking for?')
        .getResponse();
    },
  };
  
  const HelpHandler = {
    canHandle(handlerInput) {
      const request = handlerInput.requestEnvelope.request;
  
      return request.type === 'IntentRequest'
        && request.intent.name === 'AMAZON.HelpIntent';
    },
    handle(handlerInput) {
      return handlerInput.responseBuilder
        .speak('This is pet match. I can help you find the perfect pet for you. You can say, I want a dog.')
        .reprompt('What size and temperament are you looking for in a dog?')
        .getResponse();
    },
  };
  
  const ExitHandler = {
    canHandle(handlerInput) {
      const request = handlerInput.requestEnvelope.request;
  
      return request.type === 'IntentRequest'
        && (request.intent.name === 'AMAZON.CancelIntent'
          || request.intent.name === 'AMAZON.StopIntent');
    },
    handle(handlerInput) {
      return handlerInput.responseBuilder
        .speak('Bye')
        .getResponse();
    },
  };
  
  const SessionEndedRequestHandler = {
    canHandle(handlerInput) {
      return handlerInput.requestEnvelope.request.type === 'SessionEndedRequest';
    },
    handle(handlerInput) {
      console.log(`Session ended with reason: ${handlerInput.requestEnvelope.request.reason}`);
  
      return handlerInput.responseBuilder.getResponse();
    },
  };
  
  const ErrorHandler = {
    canHandle() {
      return true;
    },
    handle(handlerInput, error) {
      console.log(`Error handled: ${handlerInput.requestEnvelope.request.type} ${handlerInput.requestEnvelope.request.type === 'IntentRequest' ? `intent: ${handlerInput.requestEnvelope.request.intent.name} ` : ''}${error.message}.`);
  
      return handlerInput.responseBuilder
        .speak('Sorry, I can\'t understand the command. Please say again.')
        .reprompt('Sorry, I can\'t understand the command. Please say again.')
        .getResponse();
    },
  };
  
  
  /* CONSTANTS */
  
  const petMatchApi = {
    hostname: 'e4v7rdwl7l.execute-api.us-east-1.amazonaws.com',
    pets: '/Test',
  };
  
  const requiredSlots = [
    'energy',
    'size',
    'temperament',
  ];
  
  const slotsMeta = {
    pet: {
      invalid_responses: [
        "I'm sorry, but I'm not qualified to match you with {0}s.",
        'Ah yes, {0}s are splendid creatures, but unfortunately owning one as a pet is outlawed.',
        "I'm sorry I can't match you with {0}s.",
      ],
      error_default: "I'm sorry I can't match you with {0}s.",
    },
  };
  
  /* HELPER FUNCTIONS */
  
  function buildPastMatchObject(response, slotValues) {
    return {
      match: response.result,
      pet: slotValues.pet.resolved,
      energy: slotValues.energy.resolved,
      size: slotValues.size.resolved,
      temperament: slotValues.temperament.resolved,
    };
  }
  
  function saveValue(options, handlerInput) {
    const key = `_${options.fieldName}`;
    const attributes = handlerInput.attributesManager.getSessionAttributes();
  
    if (options.append && attributes[key]) {
      attributes[key].push(options.data);
    } else if (options.append) {
      attributes[key] = [options.data];
    } else {
      attributes[key] = options.data;
    }
  }
  
  function getSlotValues(filledSlots) {
    const slotValues = {};
  
    console.log(`The filled slots: ${JSON.stringify(filledSlots)}`);
    Object.keys(filledSlots).forEach((item) => {
      const name = filledSlots[item].name;
  
      if (filledSlots[item] &&
        filledSlots[item].resolutions &&
        filledSlots[item].resolutions.resolutionsPerAuthority[0] &&
        filledSlots[item].resolutions.resolutionsPerAuthority[0].status &&
        filledSlots[item].resolutions.resolutionsPerAuthority[0].status.code) {
        switch (filledSlots[item].resolutions.resolutionsPerAuthority[0].status.code) {
          case 'ER_SUCCESS_MATCH':
            slotValues[name] = {
              synonym: filledSlots[item].value,
              resolved: filledSlots[item].resolutions.resolutionsPerAuthority[0].values[0].value.name,
              isValidated: true,
            };
            break;
          case 'ER_SUCCESS_NO_MATCH':
            slotValues[name] = {
              synonym: filledSlots[item].value,
              resolved: filledSlots[item].value,
              isValidated: false,
            };
            break;
          default:
            break;
        }
      } else {
        slotValues[name] = {
          synonym: filledSlots[item].value,
          resolved: filledSlots[item].value,
          isValidated: false,
        };
      }
    }, this);
  
    return slotValues;
  }
  
  function randomPhrase(array) {
    return (array[Math.floor(Math.random() * array.length)]);
  }
  
  
  function buildPetMatchParams(slotValues) {
    return [
      ['SSET',
        `canine-${slotValues.energy.resolved}-${slotValues.size.resolved}-${slotValues.temperament.resolved}`],
    ];
  }
  
  function buildQueryString(params) {
    let paramList = '';
    params.forEach((paramGroup, index) => {
      paramList += `${index === 0 ? '?' : '&'}${encodeURIComponent(paramGroup[0])}=${encodeURIComponent(paramGroup[1])}`;
    });
    return paramList;
  }
  
  function buildHttpGetOptions(host, path, port, params) {
    return {
      hostname: host,
      path: path + buildQueryString(params),
      port,
      method: 'GET',
    };
  }
  
  function buildPetMatchOptions(slotValues) {
    const params = buildPetMatchParams(slotValues);
    const port = 443;
    return buildHttpGetOptions(petMatchApi.hostname, petMatchApi.pets, port, params);
  }
  
  
  function httpGet(options) {
    return new Promise(((resolve, reject) => {
      const request = https.request(options, (response) => {
        response.setEncoding('utf8');
        let returnData = '';
  
        if (response.statusCode < 200 || response.statusCode >= 300) {
          return reject(new Error(`${response.statusCode}: ${response.req.getHeader('host')} ${response.req.path}`));
        }
  
        response.on('data', (chunk) => {
          returnData += chunk;
        });
  
        response.on('end', () => {
          resolve(JSON.parse(returnData));
        });
  
        response.on('error', (error) => {
          reject(error);
        });
      });
      request.end();
    }));
  }
  
  
  const skillBuilder = Alexa.SkillBuilders.custom();
  
  /* LAMBDA SETUP */
  exports.handler = skillBuilder
    .addRequestHandlers(
      LaunchRequestHandler,
      MythicalCreaturesHandler,
      InProgressPetMatchIntent,
      CompletedPetMatchIntent,
      HelpHandler,
      FallbackHandler,
      ExitHandler,
      SessionEndedRequestHandler,
    )
    .addErrorHandlers(ErrorHandler)
    .lambda();
  