# Description:
#  Orderly incident coordination through hubot
#
# Dependencies:
#   "<module name>": "<module version>"
#
# Configuration:
#
# Notes:
#
# Authors:
#   Aaron Blythe
#   Levi Smith

# Dependencies
moment = require('moment')
checklists = require('./documentation/checklist_md')
pagerduty = require('./pagerduty/pagerduty')

# Envrionment Variables
incidentRoom     = process.env.HUBOT_INCIDENT_PAGERDUTY_ROOM
pagerDutyUserId  = process.env.HUBOT_PAGERDUTY_USER_ID

##### Functions
module.exports =
  # TODO: find a way to remove 'msg'
  trackIncident: (incidentNumber, msg, robot) ->
    #is inicident being tracked yet?
    for k,v of robot.brain.data.incidents
      if k == incidentNumber
        robot.messageRoom incidentRoom, "incident #{k} is already being tracked"
        return
    # Check that incient is open in PagerDuty
    this.checkIfIncidentOpen msg, incidentNumber, 'triggered,acknowledged', robot, (cb) ->
      if cb == null
        return
      incidentHash = {}
      incidentHash['start_time'] = moment()
      incidentHash['ack_time']
      incidentHash['resolve_time'] = ""
      incidentHash['unacknowledge_time'] = ""
      incidentHash['assign_time'] = ""
      incidentHash['escalate_time'] = ""
      # pagerduty known times
      incidentHash['pd_trigger_time'] = ""
      incidentHash['pd_ack_time'] = ""
      incidentHash['pd_resolve_time'] = ""
      incidentHash['pd_unacknowledge_time'] = ""
      incidentHash['pd_assign_time'] = ""
      incidentHash['pd_escalate_time'] = ""
      incidentHash['duration'] = ""
      incidentHash['duration_seconds'] = 0
      incidentHash['status'] = "open"
      incidentHash['log'] = ""
      incidentHash
      #this.buildIncidentHash(incidentNumber, incidentHash) ->
      robot.brain.data.incidents[incidentNumber] = incidentHash
      robot.messageRoom incidentRoom, "INCIDENT NOTIFY: Incident #{incidentNumber} has been is open and is now being tracked."
      robot.messageRoom incidentRoom, "Bot has started logging all conversation in this room as of #{robot.brain.data.incidents[incidentNumber]['start_time']}"
      checklists.getChecklist 'start', (err, content) ->
        if err?
          robot.emit 'error', err, msg
          return
        block = "```\n"
        block += content
        block += "```\n"
        robot.messageRoom incidentRoom, block

  # TODO: find a way to remove 'msg'
  resolveIncident: (incidentNumber, msg, robot) ->
    #is inicident being currently open?
    if robot.brain.data.incidents[incidentNumber]?['status'] != 'open'
      robot.messageRoom incidentRoom, "Issue #{incidentNumber} is not currently being tracked."
      return
    incidentHash = robot.brain.data.incidents[incidentNumber]
    incidentHash['resolve_time'] = moment()
    duration = this.calculateDuration(incidentHash['start_time'],incidentHash['resolve_time'])
    incidentHash['duration'] = duration
    robot.messageRoom incidentRoom, "INCIDENT NOTIFY: Resolved incident #{incidentNumber}, Incident duration #{duration}"
    incidentHash['status'] = "resolved"
    checklists.getChecklist 'end', (err, content) ->
      if err?
        robot.emit 'error', err, msg
        return
      block = "```\n"
      block += content
      block += "```\n"
      robot.messageRoom incidentRoom, block

    #delete robot.brain.data.incidents[incidentNumber]

  # Store timestamps in epoch (milliseconds from epoch)
  # Store durations in seconds
  # This makes the maths easier later
  # Use moment functions for display
  buildIncidentHash: (incidentNumber, incidentHash, cb) ->
    incidentHash = {}
    # bot known times
    incidentHash['start_time'] = moment()
    incidentHash['ack_time']
    incidentHash['resolve_time'] = ""
    incidentHash['unacknowledge_time'] = ""
    incidentHash['assign_time'] = ""
    incidentHash['escalate_time'] = ""
    # pagerduty known times
    incidentHash['pd_trigger_time'] = ""
    incidentHash['pd_ack_time'] = ""
    incidentHash['pd_resolve_time'] = ""
    incidentHash['pd_unacknowledge_time'] = ""
    incidentHash['pd_assign_time'] = ""
    incidentHash['pd_escalate_time'] = ""
    incidentHash['duration'] = ""
    incidentHash['duration_seconds'] = 0
    incidentHash['status'] = "open"
    incidentHash['log'] = ""
    incidentHash
    cb(incidentHash)

  updateTimestamp: (incidentNumber, type, timestamp, robot) ->
    if robot.brain.data.incidents[incidentNumber]
      incidentHash = robot.brain.data.incidents[incidentNumber]
      incidentHash[type] = timestamp
    else 
      log_message = "Issue setting timestamp for #{type} on incident #{incidentNumber} into hubot brain"
      console.log log_message
      robot.messageRoom incidentRoom, log_message

  formatMarkDown: (content) ->
    block = "```\n"
    block += content
    block += "```\n"
    block

  ##### Pager Duty interaction
  getPagerDutyServiceUser: (msg, required, robot, cb) ->
    if typeof required is 'function'
      cb = required
      required = true
    pagerduty.get "/users/#{pagerDutyUserId}", (err, json) ->
      if err?
        robot.emit 'error', err, msg
        return

      if json.user.id != pagerDutyUserId
        robot.messageRoom incidentRoom, "Sorry, I expected to get 1 user back for #{pagerDutyUserId}, but got #{json.user.id} :sweat:. If the bot user for PagerDuty's ID is not #{pdServiceEmail} please reconfigure"
        return

      cb(json.user)

  postNoteToPagerDuty: (msg, incidentNumber, note, robot) ->
    if pagerduty.missingEnvironmentForApi(msg)
      #TODO: error handling
      robot.messageRoom incidentRoom, "PagerDuty setup needs work."
    else
      this.getPagerDutyServiceUser msg, (user) ->
        userId = user.id
        return unless userId

        data =
          note:
            content: note
          requester_id: userId

        pagerduty.post "/incidents/#{incidentNumber}/notes", data, (err, json) ->
          if err?
            robot.emit 'error', err, msg
            return

          #if json && json.note
          #  robot.messageRoom incidentRoom, "Transcript of room added to Pagerduty note since #{incidentHash['start_time']}"
          #else
          #  robot.messageRoom incidentRoom, "Sorry, could not add transcript of room to PagerDuty as note."

  checkIfIncidentOpen: (msg, incidentNumber, statusFilter, robot, cb) ->
    pagerduty.getIncidents statusFilter, (err, incidents) ->
      if err?
        robot.emit 'error', err, msg
        cb null
        return

      foundIncidents = []
      for incident in incidents
        # FIXME this isn't working very consistently
        if Number(incidentNumber) == Number(incident.incident_number)
          foundIncidents.push(incident)

      if foundIncidents.length == 0
        robot.messageRoom incidentRoom, "Couldn't find incident(s) #{incidentNumber}. Use `#{robot.name} pager incidents` for listing. \n Tracking can only be started on unresolved incidents."
        cb null
        return
      else
        cb true
        return

  ##### Moment calculations
  calculateDuration: (start, end) ->
    Math.floor(moment.duration(moment(end,"YYYYMMDDTHHmmss").diff(moment(start,"YYYYMMDDTHHmmss"))).asHours())+moment.utc(moment(end,"YYYYMMDDTHHmmss").diff(moment(start,"YYYYMMDDTHHmmss"))).format(":mm:ss")
  
  getCurrentTime: () ->
    now = moment()
    time = now.format('YYYY-MM-DD HH:mm:ss Z')
