'use strict';
var path = require('path');

var _ = require('underscore');

var h = require('../helper');
var file = require('../file');
var chalk = require('../chalk');
var config = require('../config');
var log = require('../log');
var Queue = require('../queue');
var core = require('../core');
var session = require('../session');

const cmd = {
  command: 'submission [keyword]',
  aliases: ['pull'],
  desc:    'Download submission code',
  builder: function(yargs) {
    return yargs
      .option('a', {
        alias:    'all',
        type:     'boolean',
        default:  false,
        describe: 'Download all questions'
      })
      .option('l', {
        alias:    'lang',
        type:     'string',
        default:  'all',
        describe: 'Filter by programming language'
      })
      .option('o', {
        alias:    'outdir',
        type:     'string',
        describe: 'Where to save submission code',
        default:  '.'
      })
      .option('x', {
        alias:    'extra',
        type:     'boolean',
        default:  false,
        describe: 'Show extra question details in submission code'
      })
      .positional('keyword', {
        type:     'string',
        default:  '',
        describe: 'Download specific question by id'
      })
      .example(chalk.yellow('leetcode submission -a -o mydir'), 'Download all to folder mydir')
      .example(chalk.yellow('leetcode submission -x -a'), 'Add descriptions in the downloaded codes')
      .example(chalk.yellow('leetcode submission -l cpp 1'), 'Download cpp submission of question 1');
  }
};

function doTask(problem, queue, cb) {
  const argv = queue.ctx.argv;

  function onTaskDone(e, msg) {
    // NOTE: msg color means different purpose:
    // - red: error
    // - green: accepted, fresh download
    // - yellow: not ac-ed, fresh download
    // - white: existed already, skip download
    log.printf('[%=4s] %-60s %s', problem.fid, problem.name,
        (e ? chalk.red('ERROR: ' + (e.msg || e)) : msg));
    if (cb) cb(e);
  }

  if (argv.extra) {
    // have to get problem details, e.g. problem description.
    core.getProblem(problem.fid, function(e, problem) {
      if (e) return cb(e);
      exportSubmission(problem, argv, onTaskDone);
    });
  } else {
    exportSubmission(problem, argv, onTaskDone);
  }
}

function exportSubmission(problem, argv, cb) {
  core.getSubmissions(problem, function(e, submissions) {
    if (e) return cb(e);
    if (submissions.length === 0)
      return cb('No submissions?');

    // get obj list contain required filetype
    submissions = submissions.filter(x => argv.lang === 'all' || argv.lang === x.lang);
    if (submissions.length === 0)
      return cb('No submissions in required language.');

    // if no accepted, use the latest non-accepted one
    const submission = submissions.find(x => x.status_display === 'Accepted') || submissions[0];
    submission.ac = (submission.status_display === 'Accepted');

    const data = _.extend({}, submission, problem);
    data.sid = submission.id;
    data.ac = submission.ac ? 'ac' : 'notac';
    const basename = file.fmt(config.file.submission, data);
    const f = path.join(argv.outdir, basename + h.langToExt(submission.lang));

    file.mkdir(argv.outdir);
    // skip the existing cached submissions
    if (file.exist(f))
      return cb(null, chalk.underline(f));

    core.getSubmission(submission, function(e, submission) {
      if (e) return cb(e);

      const opts = {
        lang: submission.lang,
        code: submission.code,
        tpl:  argv.extra ? 'detailed' : 'codeonly'
      };
      file.write(f, core.exportProblem(problem, opts));
      cb(null, submission.ac ? chalk.green.underline(f)
                             : chalk.yellow.underline(f));
    });
  });
}

cmd.handler = function(argv) {
  session.argv = argv;
  const q = new Queue(null, {argv: argv}, doTask);

  if (argv.all) {
    core.getProblems(function(e, problems) {
      if (e) return log.fail(e);
      problems = problems.filter(x => x.state === 'ac' || x.state === 'notac');
      q.addTasks(problems).run();
    });
    return;
  }

  if (!argv.keyword)
    return log.fail('missing keyword?');

  core.getProblem(argv.keyword, function(e, problem) {
    if (e) return log.fail(e);
    q.addTask(problem).run();
  });
};

module.exports = cmd;