var gulp = require('gulp');
var source = require('vinyl-source-stream'); // Used to stream bundle for further handling
var browserify = require('browserify');
var watchify = require('watchify');
var reactify = require('reactify');
var gulpif = require('gulp-if');
var uglify = require('gulp-uglifyjs');
var notify = require('gulp-notify');
var concat = require('gulp-concat');
var less = require('gulp-less');
var livereload = require('gulp-livereload');
var cssmin = require('gulp-cssmin');
var imagemin = require('gulp-imagemin');
var gutil = require('gulp-util');
var shell = require('gulp-shell');
var plumber = require('gulp-plumber');
var sourcemaps = require('gulp-sourcemaps');
var glob = require('glob');
var runSequence = require('run-sequence');
var ecstatic = require('ecstatic');
var downloadatomshell = require('gulp-download-atom-shell');
var packagejson = require('./package.json');
var http = require('http');
var react = require('gulp-react');
var fs = require('fs');

var dependencies = Object.keys(packagejson.dependencies);
var devDependencies = Object.keys(packagejson.devDependencies);
var options = {
  dev: process.argv.indexOf('release') === -1 && process.argv.indexOf('test') === -1,
  test: process.argv.indexOf('test') !== -1,
  filename: 'Kitematic.app',
  name: 'Kitematic',
  signing_identity: fs.readFileSync('./identity')
};

gulp.task('js', function () {
  gulp.src('./app/**/*.js')
    .pipe(plumber(function(error) {
      gutil.log(gutil.colors.red('Error (' + error.plugin + '): ' + error.message));
      // emit the end event, to properly end the task
      this.emit('end');
    }))
    .pipe(react())
    .pipe(gulp.dest(options.dev ? './build' : './dist/osx/' + options.filename + '/Contents/Resources/app/build'))
    .pipe(gulpif(options.dev, livereload()));
});

gulp.task('specs', function () {
  var bundler = browserify({
    entries: glob.sync('./specs/**/*-spec.js'),
    debug: true, // Gives us sourcemapping
    transform: [reactify],
    cache: {}, packageCache: {}, fullPaths: true // Requirement of watchify
  });

  dependencies.forEach(function (dep) {
    bundler.external(dep);
  });

  devDependencies.forEach(function (dep) {
    bundler.external(dep);
  });

  bundler.external('./app');

  bundler.bundle()
    .on('error', gutil.log)
    .pipe(source('specs.js'))
    .pipe(gulp.dest('./build'));

  gulp.src('./specs/specs.html')
    .pipe(gulp.dest('./build'));
});

gulp.task('images', function() {
  return gulp.src('./app/images/*')
    .pipe(imagemin({
      progressive: true,
      interlaced: true,
      svgoPlugins: [{removeViewBox: false}]
    }))
    .pipe(gulp.dest(options.dev ? './build' : './dist/osx/' + options.filename + '/Contents/Resources/app/build'))
    .pipe(gulpif(options.dev, livereload()));
});

gulp.task('styles', function () {
  return gulp.src('app/styles/main.less')
    .pipe(plumber(function(error) {
      gutil.log(gutil.colors.red('Error (' + error.plugin + '): ' + error.message));
      // emit the end event, to properly end the task
      this.emit('end');
    }))
    .pipe(gulpif(options.dev, sourcemaps.init()))
    .pipe(less())
    .pipe(gulpif(options.dev, sourcemaps.write()))
    .pipe(gulp.dest(options.dev ? './build' : './dist/osx/' + options.filename + '/Contents/Resources/app/build'))
    .pipe(gulpif(!options.dev, cssmin()))
    .pipe(concat('main.css'))
    .pipe(gulpif(options.dev && !options.test, livereload()));
});

gulp.task('download', function (cb) {
  downloadatomshell({
    version: packagejson['atom-shell-version'],
    outputDir: 'cache'
  }, cb);
});

gulp.task('copy', function () {
  gulp.src('./app/index.html')
    .pipe(gulp.dest(options.dev ? './build' : './dist/osx/' + options.filename + '/Contents/Resources/app/build'))
    .pipe(gulpif(options.dev, livereload()));

  gulp.src('./app/fonts/**')
    .pipe(gulp.dest(options.dev ? './build' : './dist/osx/' + options.filename + '/Contents/Resources/app/build'))
    .pipe(gulpif(options.dev, livereload()));
});

gulp.task('dist', function (cb) {
  var stream = gulp.src('').pipe(shell([
    'rm -Rf ./dist',
    'mkdir -p ./dist/osx',
    'cp -R ./cache/Atom.app ./dist/osx/<%= filename %>',
    'mv ./dist/osx/<%= filename %>/Contents/MacOS/Atom ./dist/osx/<%= filename %>/Contents/MacOS/<%= name %>',
    'mkdir -p ./dist/osx/<%= filename %>/Contents/Resources/app',
    'cp -R browser dist/osx/<%= filename %>/Contents/Resources/app',
    'cp package.json dist/osx/<%= filename %>/Contents/Resources/app/',
    'mkdir -p dist/osx/<%= filename %>/Contents/Resources/app/resources',
    'cp -v resources/* dist/osx/<%= filename %>/Contents/Resources/app/resources/ || :',
    'cp kitematic.icns dist/osx/<%= filename %>/Contents/Resources/atom.icns',
    '/usr/libexec/PlistBuddy -c "Set :CFBundleVersion <%= version %>" dist/osx/<%= filename %>/Contents/Info.plist',
    '/usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName <%= name %>" dist/osx/<%= filename %>/Contents/Info.plist',
    '/usr/libexec/PlistBuddy -c "Set :CFBundleName <%= name %>" dist/osx/<%= filename %>/Contents/Info.plist',
    '/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier <%= bundle %>" dist/osx/<%= filename %>/Contents/Info.plist',
    '/usr/libexec/PlistBuddy -c "Set :CFBundleExecutable <%= name %>" dist/osx/<%= filename %>/Contents/Info.plist'
    ], {
      templateData: {
        filename: options.filename,
        name: options.name,
        version: packagejson.version,
        bundle: 'com.kitematic.app'
      }
  }));

  dependencies.forEach(function (d) {
    stream = stream.pipe(shell([
      'cp -R node_modules/' + d + ' dist/osx/<%= filename %>/Contents/Resources/app/node_modules/'
    ], {
      templateData: {
        filename: options.filename
      }
    }));
  });

  return stream;
});

gulp.task('sign', function () {
  return gulp.src('').pipe(shell([
    'codesign --deep --force --verbose --sign "' + options.signing_identity + '" ' + options.filename
  ], {
    cwd: './dist/osx/'
  }));
});

gulp.task('zip', function () {
  return gulp.src('').pipe(shell([
    'ditto -c -k --sequesterRsrc --keepParent ' + options.filename + ' ' + options.name + '-' + packagejson.version + '.zip'
  ], {
    cwd: './dist/osx/'
  }));
});

gulp.task('release', function () {
  runSequence('download', 'dist', ['copy', 'images', 'js', 'styles'], 'sign', 'zip');
});

gulp.task('test', ['download', 'copy', 'js', 'images', 'styles', 'specs'], function () {
  var env = process.env;
  env.NODE_ENV = 'development';
  gulp.src('').pipe(shell(['./cache/Atom.app/Contents/MacOS/Atom . --test'], {
    env: env
  }));
});

gulp.task('default', ['download', 'copy', 'js', 'images', 'styles'], function () {
  gulp.watch('./app/**/*.js', ['js']);
  gulp.watch('./app/**/*.html', ['copy']);
  gulp.watch('./app/styles/**/*.less', ['styles']);
  gulp.watch('./app/images/**', ['images']);

  livereload.listen();

  var env = process.env;
  env.NODE_ENV = 'development';
  gulp.src('').pipe(shell(['./cache/Atom.app/Contents/MacOS/Atom .'], {
    env: env
  }));
});