import { _, lazy_require, path, fsAsync } from 'azk';
import { async, originalDefer } from 'azk/utils/promises';
import { DockerBuildError } from 'azk/utils/errors';
import { spawn } from "child_process";

export function build(docker, options) {
  return async(function* () {
    var opts = _.extend({
      cache: true
    }, options);

    // Check if "Dockerfile" exist
    var dockerfile = opts.dockerfile;
    if (!(yield fsAsync.exists(dockerfile))) {
      throw new DockerBuildError('cannot_find_dockerfile', { dockerfile });
    }

    if (_.isEmpty(opts.tag)) {
      throw Error("Not build a image with a empty tag");
    }

    var cwd = path.dirname(dockerfile);

    // Options and defer
    var done = originalDefer();

    var build_options = [ "build", "-t", opts.tag, "--force-rm" ];

    if (opts.nocache) build_options.push("--no-cache");

    if (!opts.verbose) build_options.push("--quiet");

    if (!_.isEmpty(opts.target)) build_options.push("--target", opts.target);

    // "--build-arg key=value" for each item in buildArgs object
    if (opts.buildArgs) {
      Object.keys(opts.buildArgs)
        .filter(key => !_.isEmpty(opts.buildArgs[key]))
        .forEach(key => build_options.push("--build-arg", `${key}=${opts.buildArgs[key]}`));
    }

    // "--secret id=key,src=value" for each item in secrets object
    if (opts.secrets) {
      Object.keys(opts.secrets)
        .filter(key => !_.isEmpty(opts.secrets[key]))
        .forEach(key => build_options.push("--secret", `id=${key},src=${opts.secrets[key]}`));
    }

    // last build arg is the context dir
    build_options.push(cwd);

    // Enable Docker BuildKit features
    process.env.DOCKER_BUILDKIT = 1;

    // minimum stuff.
    var spawn_cmd = spawn('docker', build_options);
    var outputs = [];

    // NOTE: most likely there will never be output from docker on stdout when buildkit is enabled
    // and we are not attached to a tty.
    // Its just how BuildKit works. The normal stdout output is really complicated
    spawn_cmd.stdout.on('data', function (data) {
      outputs.push(data);

      if (opts.verbose && opts.stdout) {
        opts.stdout.write(data);
      }
    });

    spawn_cmd.stderr.on('data', function (data) {
      outputs.push(data);

      if (opts.verbose && opts.stdout) {
        opts.stdout.write(data);
      }
    });

    spawn_cmd.on('close', function (code) {
      if (code !== 0) {
        done.reject(new DockerBuildError('command_error', { dockerfile, output: outputs.join("\n") }));
      } else {
        done.resolve(docker.findImage(opts.tag))
      }
    });

    return done.promise;
  });
}

@@ -754,16 +754,22 @@
 ions = %5B
+%0A     
  %22build%22
@@ -769,16 +769,73 @@
 %22build%22,
+%0A      %22--network%22, %22host%22,%0A      %22-f%22, dockerfile,%0A     
  %22-t%22, o
@@ -842,16 +842,22 @@
 pts.tag,
+%0A     
  %22--forc
@@ -861,16 +861,21 @@
 orce-rm%22
+,%0A   
  %5D;%0A%0A   

Support custom dockerfile names, use same build options as other tooling