import { existsSync, writeFileSync } from 'fs';
import { execFile } from 'child_process';
import { promisify } from 'util';
import { CliTerseError } from '@alwaysai/alwayscli';

import mkdirp = require('mkdirp');
import { dirname } from 'path';
import {
  PRIVATE_KEY_FILE_PRETTY_PATH,
  PRIVATE_KEY_FILE_PATH,
  PUBLIC_KEY_FILE_PATH,
  PUBLIC_KEY_FILE_PRETTY_PATH
} from '../../paths';
import { ALWAYSAI_OS_PLATFORM } from '../../environment';
import { UnableToProceedWithoutMessage, Spinner } from '../../util';
import { confirmWriteFilePromptComponent } from './confirm-write-file-prompt-component';

const WRITE_MESSAGE = `Write ${PRIVATE_KEY_FILE_PRETTY_PATH}`;
export const PUBLIC_KEY_FILE_COMMENT = 'Generated by the alwaysAI CLI';

export async function findOrWritePrivateKeyFileComponent(props: {
  yes: boolean;
}) {
  const { yes } = props;
  if (existsSync(PRIVATE_KEY_FILE_PATH)) {
    // Make sure that the public part of the key is in place. It should be if it
    // was created with ssh-keygen. It might not be if the private key was
    // copied to this host from elsewhere.
    if (!existsSync(PUBLIC_KEY_FILE_PATH)) {
      const confirmed =
        yes ||
        (await confirmWriteFilePromptComponent({
          fileName: PUBLIC_KEY_FILE_PRETTY_PATH,
          description: 'Public key file'
        }));
      if (!confirmed) {
        throw new CliTerseError(
          UnableToProceedWithoutMessage(PUBLIC_KEY_FILE_PATH)
        );
      }
      const spinner = Spinner(`Write ${PUBLIC_KEY_FILE_PRETTY_PATH}`);
      try {
        const { stdout } = await promisify(execFile)('ssh-keygen', [
          '-y',
          '-f',
          PRIVATE_KEY_FILE_PATH
        ]);
        await writeFileSync(PUBLIC_KEY_FILE_PATH, stdout, { flag: 'wx' });
        spinner.succeed();
      } catch (exception) {
        if (exception.code === 'EEXIST') {
          spinner.succeed();
          // Unlikely scenario that the file did not exist but now does
        } else {
          spinner.fail();
          throw exception;
        }
      }
    }
  } else {
    // !exists
    const confirmed =
      yes ||
      (await confirmWriteFilePromptComponent({
        fileName: PRIVATE_KEY_FILE_PRETTY_PATH,
        description: 'Private key file'
      }));
    if (!confirmed) {
      throw new CliTerseError(
        UnableToProceedWithoutMessage(PRIVATE_KEY_FILE_PRETTY_PATH)
      );
    }

    // ssh-keygen does not automatically create the .ssh directory on Windows if
    // it does not already exist. On non-Windows let's just let ssh-keygen
    // create the directory so that it has proper permissions.
    if (ALWAYSAI_OS_PLATFORM === 'win32') {
      mkdirp.sync(dirname(PRIVATE_KEY_FILE_PATH));
    }

    // ssh-keygen creates the private key file and the corresponding .pub file
    const spinner = Spinner(WRITE_MESSAGE);
    try {
      await promisify(execFile)('ssh-keygen', [
        '-q',
        '-b',
        '2048',
        '-t',
        'rsa',
        '-N',
        '',
        '-C',
        PUBLIC_KEY_FILE_COMMENT,
        '-f',
        PRIVATE_KEY_FILE_PATH
      ]);
      spinner.succeed();
    } catch (exception) {
      spinner.fail();
      throw exception;
    }
  }
}
