delegate = require('dom-delegate')
calendar_templ = require('./calendar.temple')
dispatcher = require('../../common/js/dispatcher')
utils = require('../../common/js/utils.coffee')
metrics = require('../../common/js/metrics.coffee')
temple_utils = require('temple-wat')
_ = require('lodash')
aggregator = require('./min_price_aggregator.coffee')
marker = require('../../common/js/marker.coffee')
moment = require('moment')
utils = require('../../common/js/utils.coffee')
short_url = require('../../common/js/short_url.coffee')
styles = require('../../common/js/styles_modifier.coffee')
presenter_module = require('./presenter.coffee')

pool = temple_utils.pool(_.extend({}, calendar_templ))

DISPLAY_DAY_COUNT = 14

adapt_search_params = (params) ->
  result =
    affiliate: marker.is_affiliate(marker.get())
    adults: params.passengers.adults
    origin_iata: params.segments[0].origin
    destination_iata: params.segments[0].destination
    direct_date: params.segments[0].date
    direct_start_date: moment(params.segments[0].date).add(-DISPLAY_DAY_COUNT/2, 'days').format('YYYY-MM-DD')
    direct_min_date: moment().format('YYYY-MM-DD')

  if result.direct_start_date < result.direct_min_date
    result.direct_start_date = result.direct_min_date

  if params.segments.length == 2 && params.segments[1].destination == params.segments[0].origin
    _.extend(result, {
      return_date: params.segments[1].date
      return_start_date: moment(params.segments[1].date).add(-DISPLAY_DAY_COUNT/2, 'days').format('YYYY-MM-DD')
      return_min_date: result.direct_min_date
    })
    if result.return_start_date < result.return_min_date
      result.return_start_date = result.return_min_date

  result

module.exports = (element) ->
  event_delegate = delegate(element)

  model =
    dicts:
      currency: 'rub'
      currencies: {}
      search_params: {}

    min_prices_params:
      affiliate: marker.is_affiliate(marker.get())

  presenter = presenter_module(model.dicts)

  view = {}

  [el, templ_obj] = pool.get('calendar')
  element.appendChild(el)

  show_loader = (container) ->
    styles(container).add('calendar-chart-loading')
    styles(container.parentElement.querySelector('.js-calendar-loader')).remove('hidden')

  hide_loader = (container) ->
    styles(container).remove('calendar-chart-loading')
    styles(container.parentElement.querySelector('.js-calendar-loader')).add('hidden')

  show_calendar = ->
    styles(element.querySelector('.js-calendar-popup')).remove('hidden')
    styles(element.querySelector('.js-calendar-overlay')).remove('hidden')
    styles(document.body).add('overflow-hidden')
    metrics.reach_goal('CALENDAR_RIGHT_COLUMN_LINK_CLICK')

  hide_calendar = ->
    styles(element.querySelector('.js-calendar-popup')).add('hidden')
    styles(element.querySelector('.js-calendar-overlay')).add('hidden')
    styles(document.body).remove('overflow-hidden')

  render_days_change = (direction, days_change) ->
    start_moment = moment(model.min_prices_params["#{direction}_start_date"], 'YYYY-MM-DD')
    new_moment = moment(start_moment).add(days_change, 'days')

    # Limits workout
    min_moment = moment(model.min_prices_params["#{direction}_min_date"], 'YYYY-MM-DD')
    max_start_moment = moment(min_moment).add(1, 'years').add(-DISPLAY_DAY_COUNT, 'days')

    if min_moment.diff(new_moment) >= 0
      model.min_prices_params["#{direction}_start_date"] = min_moment.format('YYYY-MM-DD')
    else if max_start_moment.diff(new_moment) <= 0
      model.min_prices_params["#{direction}_start_date"] = max_start_moment.format('YYYY-MM-DD')
    else
      model.min_prices_params["#{direction}_start_date"] = new_moment.format('YYYY-MM-DD')

    show_loader(element.querySelectorAll('.js-calendar-bar-container')[{'direct': 0, 'return': 1}[direction]])
    # Show loader here
    fetch_new_data(->
      for el in element.querySelectorAll('.js-calendar-bar-container')
        hide_loader(el)
    )

  fetch_new_data = (cb, cache_only = false) ->
    callback = (params, prices) ->
      {selected_days, start_days} = adapt_present_days(model.min_prices_params)

      view = presenter.adapt(prices, selected_days, start_days)
      templ_obj.update(view)

    aggregator.fetch(model.min_prices_params, callback, (params, prices) ->
      callback(params, prices)
      cb() if cb
    , cache_only)

  adapt_present_days = (min_prices_params) ->
    result =
      selected_days:
        direct: min_prices_params.direct_date
      start_days:
        direct: min_prices_params.direct_start_date

    if min_prices_params.return_date
      result.selected_days.return = min_prices_params.return_date
      result.start_days.return = min_prices_params.return_start_date

    result

  dispatcher.on('start_search', (event, {request_id, params}) ->
    model.dicts.search_params = _.clone(params)
    model.min_prices_params = adapt_search_params(params)
    aggregator.flush()
    fetch_new_data()
  )

  dispatcher.on('search_expired', ->
    hide_calendar()
  )

  dispatcher.on('places_restored', (event, params) ->
    model.dicts.search_params.segments = _.clone(params.segments)
    fetch_new_data(null, true)
  )

  dispatcher.on('cheapest_ticket_updated', (event, {request_id, ticket}) ->
    {selected_days, start_days} = adapt_present_days(model.min_prices_params)

    view = presenter.adapt(aggregator.cheap_ticket_prices(model.min_prices_params, ticket), selected_days, start_days)
    templ_obj.update(view)
  )

  event_delegate.on('click', '.js-calendar-month-prev', (event, event_target) ->
    metrics.reach_goal('CALENDAR_PREV_MONTH_ARROW_CLICK')
    render_days_change(event_target.getAttribute('data-direction'), -DISPLAY_DAY_COUNT)
  )

  event_delegate.on('click', '.js-calendar-month-next', (event, event_target) ->
    metrics.reach_goal('CALENDAR_NEXT_MONTH_ARROW_CLICK')
    render_days_change(event_target.getAttribute('data-direction'), +DISPLAY_DAY_COUNT)
  )

  # Show/hide handle
  event_delegate.on('click', '.js-calendar-link-column', show_calendar)
  event_delegate.on('click', '.js-calendar-close', hide_calendar)
  delegate(document).on('click', '.js-calendar-overlay', hide_calendar)

  # Select day
  event_delegate.on('click', '.js-calendar-day', (event, event_target) ->
    # A little bit hack cuz of class names access :/
    if styles(event_target).contains('calendar-day-inactive')
      metrics.reach_goal('CALENDAR_INACTIVE_DAY_CLICK')
      return event.stopPropagation()

    metrics.reach_goal('CALENDAR_DAY_CLICK')
    direction = event_target.parentElement.getAttribute('data-direction')
    model.min_prices_params["#{direction}_date"] = event_target.getAttribute('data-date')

    # Show loader opposite chart only on rt
    if model.min_prices_params.return_date
      show_loader(element.querySelectorAll('.js-calendar-bar-container')[{'direct': 1, 'return': 0}[direction]])

    fetch_new_data(->
      for el in element.querySelectorAll('.js-calendar-bar-container')
        hide_loader(el)
    )
  )

  event_delegate.on('mouseout', '.js-calendar-day', (event, event_target) ->
    info_el = element.querySelector('.js-calendar-price')
    direct_date = info_el.getAttribute('data-direct-date')
    return_date = info_el.getAttribute('data-return-date')
    price = info_el.getAttribute('data-price')

    templ_obj.update(presenter.adapt_hover({direct_date, return_date}, price))
  )

  event_delegate.on('mouseover', '.js-calendar-day', (event, event_target) ->
    date = event_target.getAttribute('data-date')
    price = event_target.getAttribute('data-price')
    direction = event_target.parentElement.getAttribute('data-direction')
    dates = if direction is 'return' then {return_date: date} else {direct_date: date}
    templ_obj.update(presenter.adapt_hover(dates, price))
  )

  # Start search
  event_delegate.on('click', '.js-calendar-search', (event, event_target) ->
    metrics.reach_goal('CALENDAR_SEARCH_BUTTON_CLICK')

    model.dicts.search_params.segments[0]['date'] = model.min_prices_params.direct_date
    if model.min_prices_params.return_date
      model.dicts.search_params.segments[1]['date'] = model.min_prices_params.return_date

    hide_calendar()

    dispatcher.send('start_search', {
      request_id: utils.generate_id()
      params: model.dicts.search_params
      filters_state: utils.filters_state_by_params(model.dicts.search_params)
    }, 'calendar')

    dispatcher.send('places_restored', model.dicts.search_params, 'calendar')

    if !_.isUndefined(window.history?.pushState)
      window.history.pushState(null, null, short_url(model.dicts.search_params))
  )

  dispatcher.on('currencies_updated', (event, {request_id, currencies}) ->
    model.dicts.currencies = currencies
    fetch_new_data(null, true)
  )

  dispatcher.on('currency_updated', (event, currency) ->
    model.dicts.currency = currency
    fetch_new_data(null, true)
  )
