import { posix } from 'path';

import { Cmd } from './types';
import { SpawnerBase } from './spawner-base';
import { GnuSpawner } from './gnu-spawner';
import { APP_DIR } from './docker-spawner';
import { ResolvePosixPath } from '../resolve-posix-path';
import { CliTerseError } from '@alwaysai/alwayscli';
import { EMPTY_DOCKER_IMAGE_ID_MESSAGE } from '../../constants';
import { getDockerRunCmd } from '../docker';
import { TargetHardware } from '../../core/app';
import { PRIVATE_KEY_FILE_PATH, REMOTE_AAI_CFG_DIR_LINUX } from '../../paths';

export function SshDockerSpawner(opts: {
  targetPath: string;
  targetHostname: string;
  dockerImageId: string;
  targetHardware?: TargetHardware;
  volumes?: string[];
  env_vars?: string[];
}) {
  const { targetPath, targetHostname, dockerImageId, targetHardware } = opts;
  if (!dockerImageId) {
    throw new CliTerseError(EMPTY_DOCKER_IMAGE_ID_MESSAGE);
  }

  const resolvePath = ResolvePosixPath(APP_DIR);
  return GnuSpawner({ resolvePath, ...SpawnerBase(translate) });

  function translate(cmd: Cmd) {
    const exe = 'ssh';
    const sshArgs: string[] = ['-i', PRIVATE_KEY_FILE_PATH];
    const systemTargetPath = posix.isAbsolute(targetPath)
      ? targetPath
      : `~/${targetPath}`;
    const containerTokenDir = cmd.superuser
      ? '/root/.config/alwaysai'
      : '/.config/alwaysai';
    const volumes = [
      `${systemTargetPath}:${APP_DIR}`,
      '/dev:/dev',
      '/etc/timezone:/etc/timezone:ro',
      '/etc/localtime:/etc/localtime:ro',
      `${REMOTE_AAI_CFG_DIR_LINUX}:${containerTokenDir}`
    ];
    if (opts.volumes) {
      volumes.push(...opts.volumes);
    }
    const env_vars: string[] = [];
    if (opts.env_vars) {
      env_vars.push(...opts.env_vars);
    }
    const dockerArgs: string[] = getDockerRunCmd({
      dockerImageId,
      remove: true,
      interactive: true,
      tty: cmd.tty,
      volumes,
      env_vars,
      user: cmd.superuser ? undefined : '$(id -u ${USER}):$(id -g ${USER})',
      targetHardware,
      workdir: resolvePath(cmd.cwd),
      exe: cmd.exe,
      exeArgs: cmd.args
    });

    if (cmd.tty) {
      sshArgs.push('-t', '-t');
    }

    if (cmd.expose5000) {
      sshArgs.push('-L', '5000:0.0.0.0:5000');
    }
    sshArgs.push(targetHostname);

    const translated: Cmd = {
      exe,
      args: [...sshArgs, 'docker', ...dockerArgs],
      input: cmd.input
    };

    return translated;
  }
}
