'use strict';

const path = require('path');
const memoizee = require('memoizee');
const inquirer = require('@serverless/utils/inquirer');
const { log } = require('@serverless/utils/log');
const resolveProviderCredentials = require('@serverless/dashboard-plugin/lib/resolve-provider-credentials');
const isAuthenticated = require('@serverless/dashboard-plugin/lib/is-authenticated');
const hasLocalCredentials = require('../../aws/has-local-credentials');
const awsRequest = require('../../aws/request');

const fsp = require('fs').promises;

const yamlExtensions = new Set(['.yml', '.yaml']);

const appPattern = /^(?:#\s*)?app\s*:.+/m;
const orgPattern = /^(?:#\s*)?org\s*:.+/m;

const ServerlessError = require('../../serverless-error');
const resolveStage = require('../../utils/resolve-stage');
const resolveRegion = require('../../utils/resolve-region');

module.exports = {
  confirm: async (message, options = {}) => {
    const name = options.name || 'isConfirmed';
    return (
      await inquirer.prompt({
        message,
        type: 'confirm',
        name,
      })
    )[name];
  },
  doesServiceInstanceHaveLinkedProvider: async ({ configuration, options }) => {
    const region = resolveRegion({ configuration, options });
    const stage = resolveStage({ configuration, options });
    let result;
    try {
      result = await resolveProviderCredentials({ configuration, region, stage });
    } catch (err) {
      if (err.statusCode && err.statusCode >= 500) {
        throw new ServerlessError(
          'Serverless Framework Dashboard is currently unavailable, please try again later',
          'DASHBOARD_UNAVAILABLE'
        );
      }
      throw err;
    }

    return Boolean(result);
  },
  awsRequest: async ({ serverless }, serviceConfig, method, params) => {
    const awsProvider = serverless && serverless.getProvider('aws');
    if (awsProvider) {
      // This method supports only direct service name input
      return awsProvider.request(
        serviceConfig.name || serviceConfig,
        method,
        params,
        serviceConfig.params
      );
    }
    return awsRequest(serviceConfig, method, params);
  },
  resolveInitialContext: ({ configuration, serviceDir }) => {
    return {
      isInServiceContext: Boolean(serviceDir),
      isLoggedIntoDashboard: isAuthenticated(),
      hasLocalAwsCredentials: hasLocalCredentials(),
      isDashboardEnabled: Boolean(configuration && configuration.org && configuration.app),
    };
  },
  writeOrgAndApp: async (
    orgName,
    appName,
    { configurationFilename, serviceDir, configuration }
  ) => {
    const configurationFilePath = path.resolve(serviceDir, configurationFilename);
    let ymlString = await (async () => {
      if (!yamlExtensions.has(path.extname(configurationFilename))) return null; // Non YAML config
      try {
        return await fsp.readFile(configurationFilePath);
      } catch (error) {
        if (error.code === 'ENOENT') return null;
        throw error;
      }
    })();

    if (!ymlString) {
      log.notice(
        'Add the following settings to your serverless configuration file:\n\n' +
          `org: ${orgName}\napp: ${appName}`
      );
      return;
    }
    ymlString = ymlString.toString();

    const appMatch = ymlString.match(appPattern);
    if (appMatch) {
      ymlString = ymlString.replace(appMatch[0], `app: ${appName}`);
    } else {
      ymlString = `app: ${appName}\n${ymlString}`;
    }

    const orgMatch = ymlString.match(orgPattern);
    if (orgMatch) {
      ymlString = ymlString.replace(orgMatch[0], `org: ${orgName}`);
    } else {
      ymlString = `org: ${orgName}\n${ymlString}`;
    }
    await fsp.writeFile(configurationFilePath, ymlString);
    configuration.org = orgName;
    if (appName) configuration.app = appName;
  },
  showOnboardingWelcome: memoizee(
    (context) => {
      log.notice(`Onboarding "${context.configuration.service}" to the Serverless Dashboard`);
      log.notice();
    },
    { length: 0 }
  ),
};
