_ = require('lodash')
dispatcher = require('../../common/js/dispatcher')
metrics = require('../../common/js/metrics.coffee')
debug_client = require('./debug_client.coffee')
monkberry = require('monkberry')

monkberry.mount(require('./debug.monk'))

DEBUG_PREFIX = ''
DUMP_METRICS_TIMEOUT = 15000 #ms

console.log '%cType %cdebug%c for debug window.', 'color:grey', 'color:#00CE00', 'color:grey'

module.exports = (root) ->
  state =
    visible: false
    tab: 'succeeded'
    search_id: null
    debug_infos: []
    gates: []
    cache_checked: if localStorage.getItem('debug') then 'checked' else ''

  gates_info = []
  log_info = {}

  view = monkberry.render 'debug', state

  view.appendTo(root)

  toggle = ->
    state.visible = !state.visible
    view.update state

  key_pressed = []
  document.addEventListener 'keydown', (event) ->
    key_pressed.push(event.keyCode)
    key_pressed.shift() if key_pressed.length > 5
    toggle() if key_pressed.join('') is '6869668571' # debug

  view.on('click', '.js-debugger-close-button', toggle)

  dispatcher.on 'gates_updated', (request_id, params) ->
    _.merge(gates_info, params.gates)

  dispatcher.on 'gates_meta_updated', (event, params) ->
    result = params.meta?.map (meta) ->
      'error': if meta.error then meta.error.tos else ''
      'count': meta.count
      'good_count': meta.good_count
      'duration': (Math.round(meta.duration * 100) / 100)
      'id': meta.id
      'name': gates_info[meta.id]?.label || meta.id
    view.update gates: state.gates = result

  dispatcher.on 'benchmark_info', (event, {func, time}) ->
    log_info["#{DEBUG_PREFIX}function_#{func}"] or= []
    log_info["#{DEBUG_PREFIX}function_#{func}"].push(time)

  setInterval ->
    for k, v of log_info
      metrics.send_metric(
        goal: k
        count: v.length
        data: _.reduce(v, (a, m, i, p) ->
          a + m / p.length
        , 0)
      )
    log_info = {}
  , DUMP_METRICS_TIMEOUT


  if window.performance?.timing
    timing = window.performance.timing
    groups =
      'Connection': [timing.connectEnd - timing.connectStart]
      'Response': [timing.responseEnd - timing.responseStart]
      'Domain Lookup': [timing.domainLookupEnd - timing.domainLookupStart]
      'Load Event': [timing.loadEventEnd - timing.loadEventStart]
      'Unload Event': [timing.unloadEventEnd - timing.unloadEventStart]
      'DOMContentLoaded Event': [timing.domContentLoadedEventEnd - timing.domContentLoadedEventStart]

    log_info["#{DEBUG_PREFIX}#{k}"] = v for k, v of groups

  #### TABS ####
  view.on 'click', '.js-tabs', (event) ->
    view.update tab: state.tab = event.target.dataset.tab


  #### SETTINGS ####
  view.on 'click', '.js-use-local-storage', (event) ->
    if event.target.checked
      localStorage.setItem('debug', true)
    else
      localStorage.removeItem('debug')

  #####  FAILED GATES #####
  dispatcher.on 'start_search', (event, {request_id, params}) ->
    state.debug_infos = []
    view.update debug_infos: present_debug_infos(state.debug_infos)

  dispatcher.on 'search_id_updated', (event, {request_id, search_id}) ->
    state.search_id = search_id.search_id

  present_debug_infos = (debug_infos) ->
    result = []
    for debug_info in _.sortBy(debug_infos, (di) -> di.blockers[0].unit_name)
      result.push blockers: _.map(debug_info.blockers, (blocker) -> {unit_name: blocker.unit_name, message: blocker.message})
    return failed_gates: result

  view.on 'click', '.js-debugger-extract-debug', ->
    if state.search_id
      debug_client(state.search_id, (debug_infos) ->
        state.debug_infos = state.debug_infos.concat(debug_infos)
        view.update debug_infos: present_debug_infos(state.debug_infos)
      )
    else
      alert "Don't have search id"


  view.on "input", ".debugger_search", (event, event_target) ->
    _.debounce((value) ->
      new_debug_infos = _.filter(state.debug_infos, (di) ->
        _.any(di.blockers, (blocker) -> blocker.unit_name.indexOf(value) != -1)
      )
      view.update debug_infos: present_debug_infos(new_debug_infos)
    , 50)(event_target.value)
