import { CodedError } from '@carnesen/coded-error';
import { getSystemId } from '../../infrastructure';
import { DEVICE_CONFIG_FILE_NAME } from '../../infrastructure/device-paths';
import { Spawner, keyMirror, logger } from '../../util';
import { DeviceConfig, validateDeviceConfig } from './device-json-file';
export const DeviceCfgErrors = keyMirror({
  TARGET_DEVICE_CONFIGURED: null,
  TARGET_DEVICE_MISMATCH: null
});

export async function writeDeviceCfgFile(args: {
  spawner: Spawner;
  deviceUuid: string;
  accessToken: string;
  idToken: string;
  refreshToken: string;
}) {
  const { spawner, deviceUuid, accessToken, idToken, refreshToken } = args;
  if (await spawner.exists(DEVICE_CONFIG_FILE_NAME)) {
    throw new CodedError(
      'Device is already configured!',
      DeviceCfgErrors.TARGET_DEVICE_CONFIGURED
    );
  }
  const contents: DeviceConfig = {
    systemId: getSystemId(),
    deviceUuid,
    accessToken,
    idToken,
    refreshToken
  };
  await spawner.mkdirp();
  await spawner.writeFile(
    DEVICE_CONFIG_FILE_NAME,
    JSON.stringify(contents, null, 2)
  );
}

export async function writeOrValidateDeviceCfgFile(args: {
  spawner: Spawner;
  deviceUuid: string;
  accessToken: string;
  idToken: string;
  refreshToken: string;
}) {
  const { spawner, deviceUuid } = args;

  if (!(await spawner.exists(DEVICE_CONFIG_FILE_NAME))) {
    await writeDeviceCfgFile(args);
    return;
  }

  const origContents = await spawner.readFile(DEVICE_CONFIG_FILE_NAME);
  let origParsed;
  try {
    origParsed = JSON.parse(origContents);
  } catch {
    await spawner.rimraf(DEVICE_CONFIG_FILE_NAME);
    await writeDeviceCfgFile(args);
    return;
  }
  if (!validateDeviceConfig(origParsed)) {
    logger.warn(
      `Invalid device config contents: ${JSON.stringify(
        validateDeviceConfig.errors,
        null,
        2
      )}`
    );
    await spawner.rimraf(DEVICE_CONFIG_FILE_NAME);
    await writeDeviceCfgFile(args);
    return;
  }
  if (origParsed.deviceUuid !== deviceUuid) {
    throw new CodedError(
      "Target device doesn't match selected device!",
      DeviceCfgErrors.TARGET_DEVICE_MISMATCH
    );
  }
}
