'use strict';

let AWS = require('aws-sdk');
let qs = require('querystring');
let doc = require('dynamodb-doc');
let dynamo = new doc.DynamoDB();
let request = require('request');

// エコーBot(slackからのメッセージをそのまま返す)
exports.handler = (event, context, callback) => {
  let token = event.slackToken;
  let body = event.body;
  let requestParams = qs.parse(body);
    
  if (token === '' || token !== requestParams.token) {
    // Tokenが一致しない場合は処理しない(不正アクセス防止)
    callback(null, "Invalid request token");
    
  } else if (requestParams.user_name === 'slackbot') {
    // Botからのメッセージには反応しない(無限ループ防止)
    callback(null, 'This event skipped because user is bot');
    
  } else {
    // Botの名前
    let botName = '@bot';
    
    // 処理対象メッセージチェックの正規表現(slackからBot宛のメンションにのみ反応する)
    let match = requestParams.text.match(new RegExp(botName + '\\s([\\s\\S]+)'));
    
    if (match) {
      // Bot に対するメッセージを処理する
      let bot = new Bot();
      bot.execute(match[1], callback);
      
    } else {
      // Bot に対するメッセージではない
      callback(null, '');
    }
  }
};

class Bot {
  
  // Bot起動
  execute(command, callback) {
    // コマンド(/echoや/cityなど)によりアクションを振り分ける
    if (command.match(/\/echo\s([\s\S]*)/)) {
      // echoアクション
      this.echo(RegExp.$1, callback);

    } else if (command.match(/\/city\s(.+)/)) {
      // cityアクション
      this.city(RegExp.$1, callback);

    } else if (command.match(/\/weather\s(.+)/)) {
      // weatherアクション
      this.weather(RegExp.$1, callback);

    } else {
      // マッチしない場合
      callback(null, {text: '/echo , /city , /weather で話しかけてください。'});
    }
  }
  
  // echoアクション
  echo(text, callback) {
    // 受信したテキストをそのまま送信
    callback(null, {text: text});
  }
  
  // cityアクション
  city(cityName, callback) {
    this.getCityId(cityName, (error, cityId) => {
      if(error) {
        callback(null, {text: 'エラーが発生しました。'});

      } else if(cityId) {
        // cityNameからcityIdが解決できた
        callback(null, {text: cityName + 'のIDは' + cityId + 'です。'});

      } else {
        // 未登録のcityName
        callback(null, {text: cityName + 'は見つかりませんでした。'});
      }
    });
  }
  
  weather(cityName, callback) {
    this.getCityId(cityName, (error, cityId) => {
      if(error) {
        callback(null, {text: 'エラーが発生しました。'});

      } else if(cityId) {
        let options = {
          url: 'http://weather.livedoor.com/forecast/webservice/json/v1?city=' + cityId,
          json: true
        }
        request(options, (error, response, body) => {
          if (!error && response.statusCode == 200) {
            callback(null, {text: '[' + body.title + ']' + body.description.text});
          }
        })

      } else {
        callback(null, {text: cityName + 'は見つかりませんでした。'});
      }

    });
  }

  getCityId(cityName, callback) {
    // cityNameからcityIdを取得する
    dynamo.getItem({
      TableName: 'Cities',
      Key: {cityName: cityName}
    }).promise().then((data) => {
      // 検索が成功した場合
      callback(null, (data.Item ? data.Item.cityId : null));

    }).catch((error) => {
      // 検索が失敗した場合
      callback(error);
    });
  }

}
