import { CliTerseError } from '@alwaysai/alwayscli';
import { join } from 'path';
import { PLEASE_REPORT_THIS_ERROR_MESSAGE } from '../../constants';
import { getTargetHardwareUuid } from '../../core/app';
import {
  DeviceCfgErrors,
  writeDeviceCfgFile,
  writeOrValidateDeviceCfgFile
} from '../../core/device';
import { AaiDevice, RemoteAaiCfg, refreshDevice } from '../../infrastructure';
import { getDeviceConfigPath } from '../../infrastructure/device-paths';
import { REMOTE_AAI_CFG_DIR_LINUX } from '../../paths';
import { SshSpawner, logger, runWithSpinner, stringifyError } from '../../util';

export async function deviceCheckAndUpdateComponent(props: {
  yes: boolean;
  targetHostname: string;
  device: AaiDevice;
  isNewDevice: boolean;
}) {
  const { targetHostname, device, isNewDevice } = props;
  const spawner = SshSpawner({
    targetHostname,
    targetPath: join(REMOTE_AAI_CFG_DIR_LINUX, getDeviceConfigPath())
  });

  const CLEAR_OLD_CONF_MESSAGE =
    "To remove old configurations from the device run 'aai device clean', and then run 'aai app configure' again.";

  if (isNewDevice) {
    await runWithSpinner(
      async () => {
        try {
          const { accessToken, refreshToken, idToken } = await refreshDevice(
            device.uuid
          );
          // Write systemId to {HOME}/.config/alwaysai/alwaysai.config.json
          const aaiConfigFile = new RemoteAaiCfg(targetHostname);
          logger.debug(
            'Remote alwaysai configuration instance created, attempting to write aai configuration file.'
          );
          await aaiConfigFile.writeAaiCfgFile();
          // Then write tokens, device UUID and systemId to {HOME}/.config/alwaysai/device{getSystemId()/alwaysai.device.json
          await writeDeviceCfgFile({
            spawner,
            deviceUuid: device.uuid,
            accessToken,
            refreshToken,
            idToken
          });
        } catch (e) {
          logger.error(stringifyError(e));
          if (e.code === DeviceCfgErrors.TARGET_DEVICE_CONFIGURED) {
            throw new CliTerseError(
              `The target device is already configured as an alwaysAI device! ${CLEAR_OLD_CONF_MESSAGE}`
            );
          } else {
            logger.error(stringifyError(e));
            throw new CliTerseError(
              `There was an error with configuring the device. ${PLEASE_REPORT_THIS_ERROR_MESSAGE}`
            );
          }
        }
      },
      [],
      'Configure device'
    );
  } else {
    await runWithSpinner(
      async () => {
        // NOTE: if hardwareId passes, write the new configuration files (assume it is the correct device)
        const hardwareId = await getTargetHardwareUuid(spawner);
        if (hardwareId !== device.hardware_ids) {
          throw new CliTerseError(
            `The target device does not match the selected device! ${CLEAR_OLD_CONF_MESSAGE}`
          );
        }
        const { accessToken, refreshToken, idToken } = await refreshDevice(
          device.uuid
        );
        try {
          // Write systemId to {HOME}/.config/alwaysai/alwaysai.config.json
          const aaiConfigFile = new RemoteAaiCfg(targetHostname);
          await aaiConfigFile.writeAaiCfgFile();
          // Then write tokens, device UUID and systemId to {HOME}/.config/alwaysai/{device folder}/alwaysai.device.json
          await writeOrValidateDeviceCfgFile({
            spawner,
            deviceUuid: device.uuid,
            accessToken,
            idToken,
            refreshToken
          });
        } catch (e) {
          if (e.code === DeviceCfgErrors.TARGET_DEVICE_MISMATCH) {
            throw new CliTerseError(
              `The target device does not match the selected device! ${CLEAR_OLD_CONF_MESSAGE}`
            );
          } else {
            logger.error(stringifyError(e));
            throw new CliTerseError(
              `There was an error with updating the device configuration. ${PLEASE_REPORT_THIS_ERROR_MESSAGE}`
            );
          }
        }
      },
      [],
      'Check and update device configuration and tokens'
    );
  }
}
