import { logger } from '../npmci.logging';
import * as plugins from './mod.plugins';
import * as NpmciEnv from '../npmci.env';
import { bash } from '../npmci.bash';
import * as paths from '../npmci.paths';

import { DockerRegistry } from './mod.classes.dockerregistry';
import * as helpers from './mod.helpers';

/**
 * class Dockerfile represents a Dockerfile on disk in npmci
 */
export class Dockerfile {
  public filePath: string;
  public repo: string;
  public version: string;
  public cleanTag: string;
  public buildTag: string;
  public containerName: string;
  public content: string;
  public baseImage: string;
  public localBaseImageDependent: boolean;
  public localBaseDockerfile: Dockerfile;
  constructor(options: { filePath?: string; fileContents?: string | Buffer; read?: boolean }) {
    this.filePath = options.filePath;
    this.repo = NpmciEnv.repo.user + '/' + NpmciEnv.repo.repo;
    this.version = helpers.dockerFileVersion(plugins.path.parse(options.filePath).base);
    this.cleanTag = this.repo + ':' + this.version;
    this.buildTag = this.cleanTag;

    this.containerName = 'dockerfile-' + this.version;
    if (options.filePath && options.read) {
      this.content = plugins.smartfile.fs.toStringSync(plugins.path.resolve(options.filePath));
    }
    this.baseImage = helpers.dockerBaseImage(this.content);
    this.localBaseImageDependent = false;
  }

  /**
   * builds the Dockerfile
   */
  public async build() {
    logger.log('info', 'now building Dockerfile for ' + this.cleanTag);
    const buildArgsString = await helpers.getDockerBuildArgs();
    const buildCommand = `docker build -t ${this.buildTag} -f ${this.filePath} ${buildArgsString} .`;
    await bash(buildCommand);
    return;
  }

  /**
   * pushes the Dockerfile to a registry
   */
  public async push(dockerRegistryArg: DockerRegistry, versionSuffix: string = null) {
    const pushTag = helpers.getDockerTagString(
      dockerRegistryArg.registryUrl,
      this.repo,
      this.version,
      versionSuffix
    );
    await bash(`docker tag ${this.buildTag} ${pushTag}`);
    await bash(`docker push ${pushTag}`);
  }

  /**
   * pulls the Dockerfile from a registry
   */
  public async pull(registryArg: DockerRegistry, versionSuffixArg: string = null) {
    const pullTag = helpers.getDockerTagString(
      registryArg.registryUrl,
      this.repo,
      this.version,
      versionSuffixArg
    );
    await bash(`docker pull ${pullTag}`);
    await bash(`docker tag ${pullTag} ${this.buildTag}`);
  }

  /**
   * tests the Dockerfile;
   */
  public async test() {
    const testFile: string = plugins.path.join(paths.NpmciTestDir, 'test_' + this.version + '.sh');
    const testFileExists: boolean = plugins.smartfile.fs.fileExistsSync(testFile);
    if (testFileExists) {
      // run tests
      await bash(
        `docker run --name npmci_test_container --entrypoint="bash" ${this.buildTag} -c "mkdir /npmci_test"`
      );
      await bash(`docker cp ${testFile} npmci_test_container:/npmci_test/test.sh`);
      await bash(`docker commit npmci_test_container npmci_test_image`);
      await bash(`docker run --entrypoint="bash" npmci_test_image -x /npmci_test/test.sh`);
      await bash(`docker rm npmci_test_container`);
      await bash(`docker rmi --force npmci_test_image`);
    } else {
      logger.log('warn', 'skipping tests for ' + this.cleanTag + ' because no testfile was found!');
    }
  }

  /**
   * gets the id of a Dockerfile
   */
  public async getId() {
    const containerId = await bash(
      'docker inspect --type=image --format="{{.Id}}" ' + this.buildTag
    );
    return containerId;
  }
}