import { join } from 'path';
import { homedir } from 'os';
import { Spawner, Cmd } from './types';
import { SpawnerBase } from './spawner-base';
import { GnuSpawner } from './gnu-spawner';
import { ResolvePosixPath } from '../resolve-posix-path';
import { CliTerseError } from '@alwaysai/alwayscli';
import { EMPTY_DOCKER_IMAGE_ID_MESSAGE } from '../../constants';
import { ALWAYSAI_OS_PLATFORM } from '../../environment';
import { getDockerRunCmd } from '../docker';
import { TargetHardware } from '../../core/app';

export const APP_DIR = '/app';

export function DockerSpawner(opts: {
  dockerImageId: string;
  targetHardware?: TargetHardware;
  volumes?: string[];
  env_vars?: string[];
}): Spawner {
  const { dockerImageId, targetHardware } = opts;
  if (!dockerImageId) {
    throw new CliTerseError(EMPTY_DOCKER_IMAGE_ID_MESSAGE);
  }
  const resolvePath = ResolvePosixPath(APP_DIR);
  const gnuSpawner = GnuSpawner({ resolvePath, ...SpawnerBase(translate) });
  return {
    ...gnuSpawner,
    rimraf(path?: string) {
      if (!path || resolvePath(path) === resolvePath()) {
        throw new Error(
          'Refusing to delete whole directory because it is mirrored'
        );
      }
      return gnuSpawner.rimraf(path);
    }
  };

  function translate(cmd: Cmd) {
    if (ALWAYSAI_OS_PLATFORM !== 'linux') {
      throw new CliTerseError('Docker is only supported on Linux');
    }
    const containerTokenDir = cmd.superuser
      ? '/root/.config/alwaysai'
      : '/.config/alwaysai';
    const volumes = [
      `${process.cwd()}:${resolvePath()}`,
      '/dev:/dev',
      '/etc/timezone:/etc/timezone:ro',
      '/etc/localtime:/etc/localtime:ro',
      `${join(homedir(), '.config', 'alwaysai')}:${containerTokenDir}`
    ];
    if (opts.volumes) {
      volumes.push(...opts.volumes);
    }
    const env_vars: string[] = [];
    if (opts.env_vars) {
      env_vars.push(...opts.env_vars);
    }
    const uid = process.getuid ? process.getuid() : '';
    const gid = process.getgid ? process.getgid() : '';

    const args = getDockerRunCmd({
      dockerImageId,
      remove: true,
      interactive: true,
      tty: cmd.tty,
      volumes,
      env_vars,
      user: cmd.superuser ? undefined : `${uid}:${gid}`,
      targetHardware,
      workdir: resolvePath(cmd.cwd),
      exe: cmd.exe,
      exeArgs: cmd.args
    });

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

    return translated;
  }
}
