import { CliTerseError } from '@alwaysai/alwayscli';
import { PLEASE_REPORT_THIS_ERROR_MESSAGE } from '../../constants';
import Sentry = require('@sentry/node');
import { promptForInput, SshSpawner, logger, stringifyError } from '../../util';
import { getTargetHardwareUuid } from '../../core/app';
import {
  CliAuthenticationClient,
  addDevice,
  CliRpcClient,
  AaiDevice
} from '../../infrastructure';
import { targetHostnameCheckComponent } from './target-hostname-check-component';

export async function deviceAddComponent(props: {
  yes: boolean;
  hostname?: string;
}): Promise<AaiDevice> {
  const { yes } = props;
  if (yes) {
    throw new CliTerseError('Adding a new device is not supported with --yes');
  }
  const { username } = await CliAuthenticationClient().getInfo();
  await enforceDevModeLimit({ username });
  const deviceMode = 'development';

  const friendlyName = await promptForInput({
    purpose: 'to choose a device friendly name',
    questions: [
      {
        type: 'text',
        name: 'name',
        message: 'Enter a device friendly name:'
      }
    ]
  });

  const hostname = await targetHostnameCheckComponent({
    targetHostname: props.hostname,
    prompt: true
  });

  const hardwareId = await getTargetHardwareUuid(
    SshSpawner({ targetHostname: hostname })
  );
  const deviceUserName = await SshSpawner({ targetHostname: hostname }).run({
    exe: 'whoami'
  });

  const deviceToAdd = {
    owner: username,
    friendly_name: friendlyName.name,
    host_name: hostname,
    device_user_name: deviceUserName,
    description: '',
    hardware_ids: hardwareId,
    device_hash: '',
    iotKeys: ''
  };
  let response;
  try {
    response = await addDevice(deviceToAdd, deviceMode);
  } catch (error) {
    logger.error(stringifyError(error));
    Sentry.captureException(error);
    throw new CliTerseError(
      `There was an error with adding a device. ${PLEASE_REPORT_THIS_ERROR_MESSAGE}`
    );
  }

  const device: AaiDevice = {
    ...deviceToAdd,
    id: response.deviceId,
    uuid: response.deviceUUID,
    mode: deviceMode,
    deleted: false,
    created_at: '',
    updated_at: '',
    cognito_device_key: ''
  };
  return device;
}

async function enforceDevModeLimit(props: { username: string }) {
  const client = CliRpcClient();
  const teams = await client.listTeamsUserIsMember({
    user_name: props.username
  });
  const teamLimits = await client.checkTeamLimits({
    team_id: teams[0].id
  });

  if (teamLimits.enforce_limits) {
    const { dev_devices } = teamLimits;
    const available =
      dev_devices.limit !== null
        ? Math.max(dev_devices.limit - dev_devices.used, 0)
        : null;
    if (!available) {
      throw new CliTerseError(`No available development devices left.`);
    }
  }
}
