#import Component from 'ember-c3/components/c3-chart'
import Ember from 'ember'
import groupBy from 'ember-group-by'
#<text text-anchor='end' transform="rotate(-90)" dx='-80' dy='0' style="opacity: 1;" x='-90' y='662'>asdf</text>
import WorkflowActionDefinitionOffsetNodes from 'ember-panda/utils/project/workflow-action-definition-offset-nodes'
{get} = Ember

GraphWrapper = Ember.Object.extend
  records: []
  absolute_value: 0
  title: Ember.computed 'records.length', 'records.firstObject.title', ->
    length = @get('records.length')
    if length > 1
      optional_text = @get('records').mapBy('title').join(' & ')
      if optional_text.length <= 49
        optional_text
      else
        actions_name = t('models.plural.workflow_action_definition')
        "#{length} #{actions_name}"
    else
      @get('records.firstObject.title')
#GraphRecordWrapper = Ember.Object.extend
#  title: Ember.computed 'record.title', 'value_shift', ->
#    title = @get('record.title')
#    title = " #{title} (#{value_shift}d)" if value_shift = @get('value_shift')
#    title

#GraphOffsetWrapper = Ember.Object.extend {}
export default Ember.Component.extend
  classNames: ['action-execution-offset-diagram-component']
  graph_height: 320
  bar_height: 20
  x_axis_space: 60
  left_space: 70
  svg_width: 1200
  window_min: null
  window_max: null

  range_start_default: null
  range_start: null
  range_end: null
  range_bounds: {min: -7, max: 7}
  range_formatter: (-> [{to: @days_offset_format.bind(@)}, {to: @days_offset_format.bind(@)}]).property()
  reference_date_day_of_week: Ember.computed.oneWay 'project.reference_date_day_of_week'
  choose_reference_date: true # choose a specific date to display as planning. Use X with migration date at specific day otherwise
  chosen_absolute_date: null
  batch_size_simulation_range: Ember.computed 'project.{batch_size_lower_value,batch_size_upper_value}',->
    {min: @get('project.batch_size_lower_value'), max: @get('project.batch_size_upper_value')}
  batch_size_simulation_value: 0
  batch_size_formatter: (-> [to: (v) -> Math.round(v)]).property()

  graph_title: Ember.computed 'window_min', 'window_max', 'range_start', 'range_end', 'chosen_absolute_date', ->
    range_min = @days_offset_format @get('range_start')
    range_max = @days_offset_format @get('range_end')
    window_min = @days_offset_format @get('window_min')
    window_max = @days_offset_format @get('window_max')
    range_addition = ''
    if range_min isnt window_min or range_max isnt window_max
      range_addition = "(visible #{range_min} t/m #{range_max})"
    base = "Showing #{t('models.workflow_action_definition')} offsets #{range_addition} having total window #{window_min} t/m #{window_max}"
    base += " for #{t('attributes.project_instance.reference_date')} #{@days_offset_format(0)}" if @get('chosen_absolute_date')
    base

  days_offset_format: (v) ->
    v = Math.round(v) # could be float from slider
    if @get('chosen_absolute_date')
      date = moment(@get('chosen_absolute_date'))
      date.add(v, 'day') if v
      date.format("D-M-YYYY")
    else
      return '' unless v
      return '' unless v and Number.isFinite(v)
      if v % 7 is 0
        v = v / 7
        if v > 0 then "X+#{v}w" else "X#{v}w"
      else
        if v > 0 then "X+#{v}" else "X#{v}"

  actions:
    range_changed: ([range_start, range_end]) ->
      [range_start, range_end] = [Math.round(range_start), Math.round(range_end)]
      @setProperties
        range_start_default: [range_start, range_end]
        range_start: range_start
        range_end: range_end
      @_setup_graph() # manual setup, do not use observable patter for range_start and range_end

    batch_size_simulation_change: (value) ->
      @setProperties
        range_start: null
        range_end: null
        batch_size_simulation_value: Math.round(value)

    hide_absolute_date_choice: ->
      @set 'chosen_absolute_date', null # important! determinse wether the labels use X or dates
      @set 'choose_reference_date', false

  init: ->
    @_super arguments...
    #@set 'batch_size_simulation_value', 0 + @get('project.batch_size_lower_value') if @get('project.batch_size_lower_value')
    @set 'batch_size_simulation_value', @get('project.batch_size_lower_value') if not @get('batch_size_simulation_value') and @get('project.batch_size_lower_value')

  didReceiveAttrs: ->
    console.log 'Reload workflow-action-offset-diagram call from didReceiveAttrs'
    Ember.run.scheduleOnce 'afterRender', @, @_setup_graph

  #_graph_observer: Ember.observer 'active_workflow_action_definitions.@each.title', 'active_workflow_action_definitions.@each.offset_value', 'range_start', 'range_end', 'batch_size_simulation_value', 'batch_size_simulation_range', 'reference_date_day_of_week', 'chosen_absolute_date', 'active_workflow_action_definitions.@each.id', ->
  _graph_observer: Ember.observer 'project.update_revision', ->
    console.log 'Reload workflow-action-offset-diagram call from observer'
    console.log "update_revision: #{@get('project.update_revision')}, range_start: #{@get('range_start')}, range_end: #{@get('range_end')}"
    Ember.run.debounce  @, @_setup_graph, 150

  _setup_graph: ->
    console.log 'Reload workflow-actions-offset-diagram'
    container_selector = '.action-execution-offset-diagram-container'
    @$(container_selector).html('')
    component = @

    return unless @get('active_workflow_action_definitions.length')
    batch_size_simulation_value = @get('batch_size_simulation_value') || 0
    reference_date_day_of_week = @get('reference_date_day_of_week')
    unless reference_date = @get('chosen_absolute_date')
      reference_date = moment()
      reference_date.day reference_date_day_of_week if reference_date_day_of_week # updates reference_date instance
    result_nodes = WorkflowActionDefinitionOffsetNodes.create
      workflow_action_definitions: @get('active_workflow_action_definitions')
      reference_date: reference_date
      batch_size: batch_size_simulation_value
    resolved_record_nodes = result_nodes.get_resolved()
    return unless get resolved_record_nodes, 'length'
    wrappers = []
    x_min = -1 # at least include zero
    x_max = 0
    batch_size_simulation_value = @get('batch_size_simulation_value')
    resolved_record_nodes.forEach (record_wrapper) ->
      if wrapper = wrappers.findBy 'absolute_value', record_wrapper.get('absolute_value')
        wrapper.get('records').push record_wrapper
      else
        absolute_value = record_wrapper.get('absolute_value')
        x_min = Math.min(x_min, absolute_value)
        x_max = Math.max(x_max, absolute_value)
        wrappers.push GraphWrapper.create
          records: Ember.A([record_wrapper])
          absolute_value: absolute_value
          date: record_wrapper.get('date')
    @set 'window_min', x_min
    @set 'window_max', x_max

    ##data = @get('workflow_action_definition_groups')
    ##return unless data.length
    #x_min = d3.min(data.mapBy('absolute_value'))
    #x_min = -1 if x_min > 0 # add space for execution line
    #x_max = d3.max(data.mapBy('absolute_value'))
    #x_max = 0 if x_max < 0
    #x_max += 1 # last ending can have duration 1 when empty

    if @get('range_bounds.min') isnt x_min or @get('range_bounds.max') isnt x_max
      @set 'range_bounds', min: x_min, max: x_max
      @set 'range_start_default', [x_min, x_max] # bounds have changed, reset starts
    else if not @get('range_start_default') # uninitialized
      @set 'range_start_default', [x_min, x_max]

    @set 'range_start', x_min unless Number.isFinite(@get('range_start'))
    @set 'range_end', x_max unless Number.isFinite(@get('range_end'))
    graph_min = @get('range_start')
    graph_max = @get('range_end')

    graph_range_width = @get('svg_width') - @get('left_space') - 22
    x = d3.scale.linear().domain([graph_min, graph_max]).range([0, graph_range_width])
    #yscale = d3.scale.linear().domain([0, @get('number_of_groups')]).range([0, @get('graph_height')])
    #y = d3.scale.ordinal().rangeRoundBands([@get('graph_height'), 0], 0.1).domain(workflow_groups.mapBy('name').reverse())

    #x = d3.scale.linear().domain([x_min, x_max]).range([0, 872])
    y = d3.scale.linear().domain([0, 1]).range([0, @get('graph_height')])

    x_ticks = wrappers.mapBy 'absolute_value'
    #data.forEach (group) ->
    #  offset = Ember.get(group, 'value')
    #  x_ticks.push offset unless offset is 0 or x_ticks.indexOf(offset) > -1
    x_ticks = x_ticks.filter( (v) -> v >= graph_min and v <= graph_max).sort(d3.ascending)
    displayed_x_ticks = []
    if x_ticks.length
      displayed_x_ticks.push x_ticks[0]
      latest_pixel_x_for_space = x(x_ticks[0])
      x_ticks.forEach (v) ->
        current_pixel_x = x(v)
        if current_pixel_x - latest_pixel_x_for_space > 14
          latest_pixel_x_for_space = current_pixel_x
          displayed_x_ticks.push v
    xAxis = d3.svg.axis()
      .orient('bottom')
      .scale(x)
      .tickSize(1)
      .tickValues(displayed_x_ticks)
      .tickFormat component.days_offset_format.bind(component)
    @$(container_selector).append '<svg></svg>'
    svg_height = @get('x_axis_space') + @get('graph_height')
    canvas = d3.select("#{container_selector} svg")
      .attr 'width', '100%'
      .attr 'height', svg_height
      .attr 'viewBox', "0 0 #{@get('svg_width')} #{svg_height}"

    lines = canvas.append('g')
      .attr('class', 'offset-lines')
      .attr('transform', "translate(#{@get('left_space')},0)")
      .selectAll('line')
      .data(x_ticks) # first element is y-axis
      .enter()
      .append('line')
      .attr(
        x1: (d) -> x(d)
        y1: 0
        x2: (d) -> x(d)
        y2: y(1)
        class: 'offset-line'
      )

    offset_text = (record_wrapper) ->
      title_text = "#{record_wrapper.get('record.workflow_group.name')} -> #{record_wrapper.get('title')}"
      offset_texts = []
      record_wrapper.get('offset_wrappers').forEach (offset_wrapper) ->
        given_offset = offset_wrapper.get('total_offset') || 0
        day_text = if Math.abs(given_offset) > 1 then t('date.unit.plural.day') else t('date.unit.day')
        offset_spec = if given_offset then "#{given_offset} #{day_text}" else 'direct'
        offset_spec += " (#{value_shift}d)" if value_shift = offset_wrapper.get('value_shift')
        if offset_base_action_title = offset_wrapper.get('record.base_workflow_action_definition.title')
          offset_base_group_title = offset_wrapper.get('record.base_workflow_action_definition.workflow_group.name')
          offset_relation_text = "#{offset_spec}: #{offset_base_group_title} -> #{offset_base_action_title}"
        else
          offset_relation_text = "#{offset_spec} from X"
        offset_texts.push "Offset: #{offset_relation_text}"
      "<button class='ui tiny icon button pull-right edit-workflow-action-definition' data-workflow-action-definition='#{record_wrapper.get('record_id')}'><i class='pencil icon'/></button>#{title_text}<br>#{offset_texts.join('<br>')}"
    texts = canvas.append('g')
      .attr('class', 'action-descriptions')
      .attr('transform', "translate(#{@get('left_space')},0)")
      .selectAll('text')
      .data(wrappers.filter((d) -> (d.get('absolute_value') >= graph_min) and (d.get('absolute_value') <= graph_max)))
      .enter()
      .append('text')
      .attr 'class', 'action-description-text'
      .attr('transform', 'rotate(-90)')
      .html (wrapper) ->
        wrapper.get('title')
      #.html (group) ->
      #  if group.items.length <= 2
      #    group.items.map( (record) ->
      #      "<tspan class='action-description-action-part' data-record-id='#{record.id}' tooltip='#{Ember.get(record, 'workflow_group.name')}'>#{Ember.get(record, 'title')}</tspan>"
      #    ).join(', ')
      #  else
      #    "<tspan>#{group.items.length} #{actions_name}</tspan>"
      .attr
        x: 10 - @get('graph_height')
        y: (d) -> x(Ember.get(d, 'absolute_value'))
        dy: -5
        dx: -5
      .on 'click', (wrapper) ->
        target = $(@)
        unless target.hasClass 'tooltipstered'
          target.tooltipster
            content: 'Loading...'
            contentAsHTML: true
            selfDestruction: false
            trigger: 'click'
            interactive: true
            functionReady: ->
              $('.tooltipster-base .edit-workflow-action-definition').on 'click', ->
                return target.tooltipster('close') unless id = $(@).data('workflowActionDefinition')
                return target.tooltipster('close') unless target_workflow_action_definition = component.store.peekRecord('panda/workflow-action-definition', id)
                component.modal 'workflow-action-definition/edit-workflow-action-definition',
                  model: target_workflow_action_definition
                target.tooltipster('close')

        record_offset_texts = wrapper.records.sortBy('record.absolute_position').map(offset_text)
        if wrapper.records.length > 1
          target.tooltipster 'content', record_offset_texts.join('<hr>')
        else
          target.tooltipster 'content', record_offset_texts[0]
        target.tooltipster 'open'

    if graph_min <= 0 <= graph_max
      base_line = canvas.append('line').attr
        x1: x(0)
        y1: 0
        x2: x(0)
        y2: 15 + @get('graph_height')
        class: 'base-line'
        transform: "translate(#{@get('left_space')},0)"

    x_xis = canvas.append('g')
      .attr('transform', "translate(#{@get('left_space')},#{@get('graph_height')})")
      .attr('class','x-axis')
      .call(xAxis)
      .selectAll('text')
        .style('text-anchor', 'end')
        .attr('dx', '-.8em')
        .attr('dy', '.15em')
        .attr('transform', "rotate(-40)")

    canvas.selectAll('.action-description-action-part').on 'click', (d) ->
      return unless workflow_action_definition_id = $(@).data('recordId')
      return unless workflow_action_definition = component.store.peekRecord('panda/workflow-action-definition', workflow_action_definition_id)
      component.modal 'workflow-action-definition/edit-workflow-action-definition',
        model: workflow_action_definition
