import { CliTerseError } from '@alwaysai/alwayscli';
import { join } from 'path';
import { PLEASE_REPORT_THIS_ERROR_MESSAGE } from '../../constants';
import { writeCertificate } from '../../core/device';
import { writeDeviceCfgFile } from '../../core/device/write-or-validate-device-cfg-file';
import { requirePaidPlan } from '../../core/project';
import {
  addDevice,
  AddedDevice,
  CliAuthenticationClient,
  LocalAaiCfg
} from '../../infrastructure';
import { DEVICE_CERTIFICATES_DIRECTORY_NAME } from '../../infrastructure/certificate-paths';
import { getDeviceConfigPath } from '../../infrastructure/device-paths';
import { AAI_CONFIG_DIRECTORY_NAME } from '../../paths';
import {
  echo,
  JsSpawner,
  logger,
  runWithSpinner,
  stringifyError
} from '../../util';
import { checkUserIsLoggedInComponent } from '../user';

export async function generateProductionDeviceFunc(props: {
  name: string;
  description?: string;
}) {
  const { name, description } = props;
  await checkUserIsLoggedInComponent({ yes: false });
  await requirePaidPlan();

  const { username } = await CliAuthenticationClient().getInfo();
  const deviceToAdd = {
    owner: username,
    friendly_name: name,
    host_name: '',
    device_user_name: '',
    description: description ?? '',
    hardware_ids: '',
    device_hash: '',
    iotKeys: ''
  };
  try {
    const response: AddedDevice = await generateDevice(deviceToAdd);
    const outDir = join(process.cwd(), response.deviceUUID);
    const aaiDir = join(outDir, AAI_CONFIG_DIRECTORY_NAME);
    const cfgDir = join(aaiDir, getDeviceConfigPath());
    await runWithSpinner(
      async () => {
        // Write tokens, deviceId and systemId to
        //    {cwd}/{UUID}/.config/alwaysai/device{getSystemId()}/alwaysai.device.json
        // and write systemId to
        //    {cwd}/{UUID}/.config/alwaysai/alwaysai.config.json
        const tokenSpawner = JsSpawner({ path: cfgDir });
        const certSpawner = JsSpawner({
          path: join(cfgDir, DEVICE_CERTIFICATES_DIRECTORY_NAME)
        });
        const aaiConfigFile = new LocalAaiCfg(aaiDir);
        await aaiConfigFile.writeAaiCfgFile();
        await writeDeviceCfgFile({
          spawner: tokenSpawner,
          deviceUuid: response.deviceUUID,
          accessToken: response.accessToken,
          refreshToken: response.refreshToken,
          idToken: response.idToken
        });
        await writeCertificate({
          spawner: certSpawner,
          certificate: response.iotKeys.certificatePem,
          privateKey: response.iotKeys.keyPair.PrivateKey,
          rootCa: response.iotKeys.rootCA
        });
      },
      [],
      `Write device credentials to ${outDir}`
    );
    echo(`Created ${name}: device ID=${response.deviceUUID}`);
    return response.deviceUUID;
  } catch (error) {
    logger.error(stringifyError(error));
    throw new CliTerseError(
      `There was an error with creating the device. ${PLEASE_REPORT_THIS_ERROR_MESSAGE}`
    );
  }
}

async function generateDevice(deviceToAdd) {
  let response;
  await runWithSpinner(
    async () => {
      response = await addDevice(deviceToAdd, 'production');
    },
    [],
    'Create new production device'
  );
  return response;
}
