"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.UseExistingPushNotification = exports.UpdateIosPush = exports.RemoveIosPush = exports.CreateIosPush = void 0;

function _chalk() {
  const data = _interopRequireDefault(require("chalk"));

  _chalk = function () {
    return data;
  };

  return data;
}

function _get() {
  const data = _interopRequireDefault(require("lodash/get"));

  _get = function () {
    return data;
  };

  return data;
}

function _prompt() {
  const data = _interopRequireDefault(require("../../prompt"));

  _prompt = function () {
    return data;
  };

  return data;
}

function _log() {
  const data = _interopRequireDefault(require("../../log"));

  _log = function () {
    return data;
  };

  return data;
}

function _credentials() {
  const data = require("../credentials");

  _credentials = function () {
    return data;
  };

  return data;
}

function _promptForCredentials() {
  const data = require("../actions/promptForCredentials");

  _promptForCredentials = function () {
    return data;
  };

  return data;
}

function _list() {
  const data = require("../actions/list");

  _list = function () {
    return data;
  };

  return data;
}

function _appleApi() {
  const data = require("../../appleApi");

  _appleApi = function () {
    return data;
  };

  return data;
}

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

const APPLE_KEYS_TOO_MANY_GENERATED_ERROR = `
You can have only ${_chalk().default.underline('two')} Push Notifactions Keys on your Apple Developer account.
Please revoke the old ones or reuse existing from your other apps.
Please remember that Apple Keys are not application specific!
`;

class CreateIosPush {
  async create(ctx) {
    const newPushKey = await this.provideOrGenerate(ctx);
    const credentials = { ...newPushKey,
      teamId: ctx.appleCtx.team.id,
      teamName: ctx.appleCtx.team.name
    };
    return await ctx.ios.createPushKey(credentials);
  }

  async open(ctx) {
    const pushKey = await this.create(ctx);
    (0, _log().default)('Successfully created Push Notification Key\n');
    (0, _list().displayIosUserCredentials)(pushKey);
    (0, _log().default)();
    return null;
  }

  async provideOrGenerate(ctx) {
    const userProvided = await (0, _promptForCredentials().askForUserProvided)(_credentials().pushKeySchema);

    if (userProvided) {
      return userProvided;
    }

    return await generatePushKey(ctx);
  }

}

exports.CreateIosPush = CreateIosPush;

class RemoveIosPush {
  constructor(shouldRevoke = false) {
    this.shouldRevoke = shouldRevoke;
  }

  async open(ctx) {
    const selected = await selectPushCredFromList(ctx.ios.credentials);

    if (!selected) {} else if (!(0, _get().default)(selected, 'type')) {
      await this.removePushCert(ctx, selected);
      (0, _log().default)(_chalk().default.green('Successfully removed Push Certificate'));
    } else {
      await this.removeSpecific(ctx, selected);
      (0, _log().default)(_chalk().default.green('Successfully removed Push Notification Key'));
    }

    return null;
  }

  async removePushCert(ctx, appCredentials) {
    await ctx.ios.deletePushCert(appCredentials.experienceName, appCredentials.bundleIdentifier);
  }

  async removeSpecific(ctx, selected) {
    const apps = getAppsUsingPushCred(ctx.ios.credentials, selected);
    const appsList = apps.map(appCred => appCred.experienceName).join(', ');

    if (appsList) {
      const {
        confirm
      } = await (0, _prompt().default)([{
        type: 'confirm',
        name: 'confirm',
        message: `Removing this key/cert will disable notifications in ${appsList}. Do you want to continue?`
      }]);

      if (!confirm) {
        (0, _log().default)('Aborting');
        return;
      }
    }

    await ctx.ios.deletePushKey(selected.id);
    const {
      revoke
    } = await (0, _prompt().default)([{
      type: 'confirm',
      name: 'revoke',
      message: `Do you also want to revoke it on Apple Developer Portal?`,
      when: !this.shouldRevoke
    }]);

    if (revoke || this.shouldRevoke) {
      await ctx.ensureAppleCtx();
      await new (_appleApi().PushKeyManager)(ctx.appleCtx).revoke([selected.apnsKeyId]);
    }
  }

}

exports.RemoveIosPush = RemoveIosPush;

class UpdateIosPush {
  async open(ctx) {
    const selected = await selectPushCredFromList(ctx.ios.credentials, false);

    if (selected) {
      await this.updateSpecific(ctx, selected);
      (0, _log().default)(_chalk().default.green('Successfully updated Push Notification Key.\n'));
      const updated = ctx.ios.credentials.userCredentials.find(i => i.id === selected.id);

      if (updated) {
        (0, _list().displayIosUserCredentials)(updated);
      }

      (0, _log().default)();
    }

    return null;
  }

  async updateSpecific(ctx, selected) {
    const apps = getAppsUsingPushCred(ctx.ios.credentials, selected);
    const appsList = apps.map(appCred => appCred.experienceName).join(', ');

    if (apps.length > 1) {
      const question = {
        type: 'confirm',
        name: 'confirm',
        message: `Update will affect all applications that are using this key (${appsList}). Do you want to continue?`
      };
      const {
        confirm
      } = await (0, _prompt().default)(question);

      if (!confirm) {
        _log().default.warn('Aborting update process');

        return;
      }
    }

    const newPushKey = await this.provideOrGenerate(ctx);
    const credentials = { ...newPushKey,
      teamId: ctx.appleCtx.team.id,
      teamName: ctx.appleCtx.team.name
    };
    await ctx.ios.updatePushKey(selected.id, credentials);
  }

  async provideOrGenerate(ctx) {
    const userProvided = await (0, _promptForCredentials().askForUserProvided)(_credentials().pushKeySchema);

    if (userProvided) {
      return userProvided;
    }

    return await generatePushKey(ctx);
  }

}

exports.UpdateIosPush = UpdateIosPush;

class UseExistingPushNotification {
  async open(ctx) {
    if (!ctx.hasProjectContext) {
      _log().default.error('Can only be used in project context');

      return null;
    }

    const experience = (0, _get().default)(ctx, 'manifest.slug');
    const experienceName = `@${ctx.user.username}/${experience}`;
    const bundleIdentifier = (0, _get().default)(ctx, 'manifest.ios.bundleIdentifier');

    if (!experience || !bundleIdentifier) {
      _log().default.error(`slug and ios.bundleIdentifier needs to be defined`);

      return null;
    }

    const filtered = ctx.ios.credentials.appCredentials.filter(app => app.experienceName === experienceName && app.bundleIdentifier === bundleIdentifier);
    const selected = await selectPushCredFromList(ctx.ios.credentials, false);

    if (selected) {
      await ctx.ios.usePushKey(experienceName, bundleIdentifier, selected.id);
      (0, _log().default)(_chalk().default.green(`Successfully assingned Push Notifactions Key to ${experienceName} (${bundleIdentifier})`));
    }

    return null;
  }

}

exports.UseExistingPushNotification = UseExistingPushNotification;

async function selectPushCredFromList(iosCredentials, allowLegacy = true) {
  const pushKeys = iosCredentials.userCredentials.filter(cred => cred.type === 'push-key');
  const pushCerts = allowLegacy ? iosCredentials.appCredentials.filter(({
    credentials
  }) => credentials.pushP12 && credentials.pushPassword) : [];
  const pushCredentials = [...pushCerts, ...pushKeys];

  if (pushCredentials.length === 0) {
    _log().default.warn('There are no push credentials available in your account');

    return null;
  }

  const getName = pushCred => {
    if ((0, _get().default)(pushCred, 'type') === 'push-key') {
      return formatPushKey(pushCred, iosCredentials);
    } else {
      const pushCert = pushCred;
      return `Push Certificate (PushId: ${pushCert.credentials.pushId || '------'}, TeamId: ${pushCert.credentials.teamId || '-------'} used in ${pushCert.experienceName})`;
    }

    return 'unkown credentials';
  };

  const question = {
    type: 'list',
    name: 'credentialsIndex',
    message: 'Select credentials from list',
    choices: pushCredentials.map((entry, index) => ({
      name: getName(entry),
      value: index
    }))
  };
  const {
    credentialsIndex
  } = await (0, _prompt().default)(question);
  return pushCredentials[credentialsIndex];
}

function getAppsUsingPushCred(iosCredentials, pushCred) {
  if ((0, _get().default)(pushCred, 'type') === 'push-key') {
    return iosCredentials.appCredentials.filter(cred => cred.pushCredentialsId === pushCred.id);
  } else if ((0, _get().default)(pushCred, 'credentials.pushP12') && (0, _get().default)(pushCred, 'credentials.pushPassword')) {
    return [pushCred];
  }

  return [];
}

function formatPushKeyFromApple(appleInfo, credentials) {
  const userCredentials = credentials.userCredentials.filter(cred => cred.type == 'push-key' && cred.apnsKeyId === appleInfo.id);
  const appCredentials = userCredentials.length !== 0 ? credentials.appCredentials.filter(cred => cred.pushCredentialsId === userCredentials[0].id) : [];
  const joinApps = appCredentials.map(i => `      ${i.experienceName} (${i.bundleIdentifier})`).join('\n');
  const usedByString = !!joinApps ? `    ${_chalk().default.gray(`used by\n${joinApps}`)}` : `    ${_chalk().default.gray(`not used by any apps`)}`;
  const {
    name,
    id
  } = appleInfo;
  const pushKey = userCredentials[0];
  const teamText = pushKey ? `, Team ID: ${pushKey.teamId || '---'}, Team name: ${pushKey.teamName || '---'}` : '';
  return `${name} - KeyId: ${id}${teamText}\n${usedByString}`;
}

function formatPushKey(pushKey, credentials) {
  const appCredentials = credentials.appCredentials.filter(cred => cred.pushCredentialsId === pushKey.id);
  const joinApps = appCredentials.map(i => `${i.experienceName} (${i.bundleIdentifier})`).join(', ');
  const usedByString = !!joinApps ? `\n    ${_chalk().default.gray(`used by ${joinApps}`)}` : `\n    ${_chalk().default.gray(`not used by any apps`)}`;
  return `Push Notifications Key (Key ID: ${pushKey.apnsKeyId}, Team ID: ${pushKey.teamId})${usedByString}`;
}

async function generatePushKey(ctx) {
  await ctx.ensureAppleCtx();
  const manager = new (_appleApi().PushKeyManager)(ctx.appleCtx);

  try {
    return await manager.create();
  } catch (e) {
    if (e.code === 'APPLE_PUSH_KEYS_TOO_MANY_GENERATED_ERROR') {
      const keys = await manager.list();

      _log().default.warn('Maximum number of Push Notifications Keys generated on Apple Developer Portal.');

      _log().default.warn(APPLE_KEYS_TOO_MANY_GENERATED_ERROR);

      const usedByExpo = ctx.ios.credentials.userCredentials.filter(cert => cert.type === 'push-key').reduce((acc, cert) => ({ ...acc,
        [cert.apnsKeyId]: cert
      }), {});
      const {
        revoke
      } = await (0, _prompt().default)([{
        type: 'checkbox',
        name: 'revoke',
        message: 'Select Push Notifications Key to revoke.',
        choices: keys.map((key, index) => ({
          value: index,
          name: formatPushKeyFromApple(key, ctx.ios.credentials)
        })),
        pageSize: Infinity
      }]);

      for (const index of revoke) {
        const certInfo = keys[index];

        if (certInfo && usedByExpo[certInfo.id]) {
          await new RemoveIosPush(true).removeSpecific(ctx, usedByExpo[certInfo.id]);
        } else {
          await manager.revoke([certInfo.id]);
        }
      }
    } else {
      throw e;
    }
  }

  return await generatePushKey(ctx);
}
//# sourceMappingURL=../../__sourcemaps__/credentials/views/IosPushCredentials.js.map