'use strict';

const BbPromise = require('bluebird');
const path = require('path');
const webpack = require('webpack');
const utils = require('./utils');

module.exports = {
  loadHandler(stats, functionId, purge) {
    const handler = this.serverless.service.functions[functionId].handler.split('.');
    const moduleFileName = `${handler[0]}.js`;
    const handlerFilePath = path.join(
      path.resolve(stats.compilation.options.output.path),
      moduleFileName
    );
    if (purge) {
      utils.purgeCache(handlerFilePath);
    }
    const module = require(handlerFilePath);
    const functionObjectPath = handler.slice(1);
    let func = module;
    for (let p of functionObjectPath) {
      func = func[p];
    }
    return func;
  },

  getEvent() {
    return this.options.path
      ? this.serverless.utils.readFileSync(this.options.path)
      : null; // TODO use get-stdin instead
  },

  getContext(functionName) {
    return {
      awsRequestId: utils.guid(),
      invokeid: utils.guid(),
      logGroupName: `/aws/lambda/${functionName}`,
      logStreamName: '2016/02/14/[HEAD]13370a84ca4ed8b77c427af260',
      functionVersion: '$LATEST',
      isDefaultFunctionVersion: true,
      functionName: functionName,
      memoryLimitInMB: '1024',
    };
  },

  run(stats) {
    const functionName = this.options.function;

    this.serverless.cli.log(`Run function ${functionName}...`);

    const handler = this.loadHandler(stats, functionName);
    const event = this.getEvent();
    const context = this.getContext(functionName);

    return new BbPromise((resolve, reject) => handler(
      event,
      context,
      (err, res) => {
        if (err) {
          reject(err);
        } else {
          resolve(res);
        }
      }
    ));
  },

  watch() {
    const functionName = this.options.function;
    this.serverless.cli.log(`Watch function ${functionName}...`);

    const compiler = webpack(this.webpackConfig);

    compiler.watch({}, (err, stats) => {
      if (err) {
        throw err;
      }
      this.serverless.cli.log(`Run function ${functionName}...`);
      const handler = this.loadHandler(stats, functionName, true);
      const event = this.getEvent();
      const context = this.getContext(functionName);
      handler(
        event,
        context,
        (err, res) => {
          if (err) {
            throw err;
          } else {
            this.serverless.cli.consoleLog(res);
          }
        }
      )
    });

    return BbPromise.resolve();
  },
};

@@ -1271,16 +1271,301 @@
 ;%0A  %7D,%0A%0A
+  setEnvironmentVars(functionName) %7B%0A    const providerEnvVars = this.serverless.service.provider.environment %7C%7C %7B%7D;%0A    const functionEnvVars = this.serverless.service.functions%5BfunctionName%5D.environment %7C%7C %7B%7D;%0A%0A    Object.assign(process.env, providerEnvVars, functionEnvVars);%0A  %7D,%0A%0A
   run(st
@@ -1829,16 +1829,59 @@
 onName);
+%0A    this.setEnvironmentVars(functionName);
 %0A%0A    re
@@ -2576,24 +2576,70 @@
 ctionName);%0A
+      this.setEnvironmentVars(functionName);%0A%0A
       handle

support environment variables on 'run'