module Dunlop
  module ApplicationHelper
    include Dunlop::ActiveClassHelper
    include Dunlop::AuthorizationHelper
    include Dunlop::TableHelper
    include Dunlop::StateBadgeHelper
    include Dunlop::InterpretedTextHelper
    delegate :mathjax_path, to: :main_app

    def application_name
      Rails.application.config.application_name || Rails.application.class.name.deconstantize
    end

    def search_result_info(records)
      from_item = (records.current_page - 1) * records.limit_value + 1
      to_item = [from_item + records.size - 1, records.total_count].min
      from_item = 0 if records.total_count.zero?
      "#{from_item} - #{to_item} / #{records.total_count}"
    end

    def body_classes
      classes = []
      classes << 'archived-mode' if session[:archived_mode]
      classes
    end

    # Use this helper to show a boolean. Then a unifor way of displaying can be implemented.
    def boolean_show(value)
      content_tag(:i, nil, class: ['boolean-show', (value.present? ? 'yes checkmark box icon' : 'no square outline icon')])
    end

    def show_address(record)
      [record.zipcode, "#{record.housenumber}#{record.housenumber_ext}"].map(&:presence).compact.join(' ')
    end

    # https://coderwall.com/p/7gqmog/display-flash-messages-with-semantic-ui-in-rails
    def flash_class(level)
      case level.to_sym
      when :success       then "ui positive message"
      when :error, :alert then "ui negative message"
      when :notice        then "ui info message"
      else "ui #{level} message"
      end
    end

    #def render_cascaded(*args)
    #  options = args.extract_options!
    #  controller_parts = controller_path.split('/')
    #  if args.first.is_a?(String) or options[:partial].present?
    #    partial_name = args.first.presence || options[:partial]
    #    lookup_name = "_#{partial_name}"
    #    controller_parts.pop until lookup_context.template_exists?(File.join(*controller_parts, lookup_name))
    #    options[:partial] = File.join(*controller_parts, partial_name)
    #    render options
    #  elsif options[:template].present?
    #    lookup_name = options[:template]
    #    controller_parts.pop until lookup_context.template_exists?(File.join(*controller_parts, lookup_name))
    #    options[:template] = File.join(*controller_parts, lookup_name)
    #    render options
    #  else
    #    render *args
    #  end
    #end

    # Try to find a template containing the workflow step info specification of the record
    # and render nothing if it cannot be found
    # an OwnerServiceWindow1Preparation::Scenario1 record will search for a template
    # named "info_fields" in the following locations:
    #   app/views/owner_service_window1_preparations/scenario1s/info_fields.html.haml
    #   app/views/owner_service_window1_preparations/info_fields.html.haml
    def record_info_fields(record, options = {})
      lookup_cascade = record.class.name.underscore.split('/').map(&:pluralize)
      lookup_name = 'info_fields'
      template_path = File.join(*lookup_cascade, lookup_name)
      until lookup_context.template_exists?(template_path) or lookup_cascade.empty?
        return if lookup_cascade.empty? # not template for record found
        lookup_cascade.pop
        template_path = File.join(*lookup_cascade, lookup_name)
      end
      render template: template_path, locals: options.merge(record: record) if lookup_context.template_exists?(template_path)
    end

    def scope_model(model = nil)
      @scope_model = model if model
      @scope_model
    end

    def at(attribute_name, scope_model=nil)
      scope_model ||= @scope_model
      scope_model.human_attribute_name(attribute_name)
    end

    def page_title(*args)
      res = content_tag :h3, class: 'page-title ui header' do
        if resource_title?(args)
          @scope_model = args[1].is_a?(ActiveRecord::Base) ? args[1].class : args[1]
          page_title_for_resource(args)
        else
          page_title_for_string(args)
        end
      end
      content_for :page_title, res
      res
    end

    def resource_title?(args)
      args.first.is_a?(Symbol) &&
        (args[1].respond_to?(:model_name) || args[1].class.respond_to?(:model_name))
    end

    def page_title_for_string(args)
      args.first
    end

    def page_title_for_resource(args)
      options = args.extract_options!
      model = args[1].respond_to?(:model_name) ? args[1] : args[1].class
      if args.first == :index
        title = t('action.index.label', models: model.model_name.human_plural)
      else
        title = t("action.#{args.first}.label", model: model.model_name.human)
      end
      if back_options = options[:back]
        url =
          case back_options
          when Array then polymorphic_path(back_options)
          when true then :back
          else back_options
          end
        if url
          back_link = link_to content_tag(:i, nil, class: 'left arrow icon'), url, class: 'title-back-link'
          title = [back_link, title].join.html_safe
        end
      end
      title
    end

    # It returns a proper array to select the hour of the day
    def hours_for_select
      (0..23).map{|v| DayTimeMinutes.new 60 * v }
    end

    # This is a wrapper to create collapsible content.
    def collapsible_content(title, options = {}, &blk)
      content = capture(&blk) if blk.present?
      content ||= options.delete(:content)
      collapsed = options.has_key?(:collapsed) ? options.delete(:collapsed) : true

      classes = Array.wrap(options[:class]) | ["collapsible-container", collapsed ? 'collapsed' : nil]
      title_tag = content_tag(:div, "<span></span>#{title}".html_safe, class: 'collapsible-title')
      content_tag(:div, title_tag + content_tag(:div, content, class: 'collapsible-content'), options.merge(class: classes))
    end

    # Need a custom one, since rails still does not support non present dates
    def dunlop_localize(date, options = {})
      return '' unless date.present?
      l(date, options)
    end

    # Return a page relative time tag. The current time is meant to be replaced by relative time from
    # the moment javascript library
    def page_time(time = Time.current)
      content_tag(:span, time, id: 'page-time', data: {time: time.utc.iso8601, format: 'relative'})
    end

    # Tested through the migration decorator
    def plan_date(options = {})
      return '' unless options[:date] or options[:window_from] or options[:window_to]
      date = options[:date].try(:strftime, '%d-%m-%Y')
      window = ''
      if options[:window_from].present? or options[:window_to].present?
        window_from_display = options[:window_from].present? ? "#{options[:window_from]}:00&nbsp;" : ''
        window_to_display = options[:window_to].present? ? "&nbsp;#{options[:window_to]}:00" : ''
        window = "&nbsp;#{content_tag(:span, '', class: 'fa fa-clock-o')}&nbsp;&nbsp;#{window_from_display}-#{window_to_display}"
      end
      "#{date} #{window}".strip.html_safe
    end

    def plan_date_for_record(record)
      return '' unless record.present?
      plan_date(
        date: record.plan_date,
        window_from: record.window_from,
        window_to: record.window_to
      )
    end

    def empty_collection(model)
      content_tag(:div, t('collection.empty', models: model.model_name.human_plural), class: 'empty-collection')
    end

    def workflow_step_buttons_for(workflow_instance_class)
      #buttons = []
      #record_class.workflow_step_classes.each do |workflow_step|
      #  next unless can?(:manage, workflow_step)
      #  base_name = workflow_step.name.underscore.split('/').first
      #  buttons << content_tag(:button, t('perform_batch_actions_button', scope: base_name), class: "#{base_name.pluralize}-actions", data: {action: 'workflow_step', workflow_step: base_name})
      #end
      #buttons.join.html_safe
      workflow_instance_class.workflow_step_classes.map{|workflow_step| workflow_step_button_for workflow_step }.compact.join.html_safe
    end

    def workflow_step_button_for(workflow_step, data_attributes = {})
      return unless can?(:manage, workflow_step)
      base_name = workflow_step.name.underscore.split('/').first
      data_attributes[:action]   ||= 'collection_edit'
      data_attributes[:resource] ||= workflow_step.name.underscore
      data_attributes[:request_params] = data_attributes[:request_params].to_json if data_attributes[:request_params].is_a?(Hash)
      data_attributes[:request_params] ||= {workflow_instance_ids: 'selected_ids'}.to_json
      text = t('workflow_step.update_button_text', models: workflow_step.model_name.human_plural)
      content = content_tag(:span, text, class: 'text') + content_tag(:span, '', class: 'icon')
      content_tag(:button, content, class: "#{base_name.pluralize}-actions workflow-step-actions collection-edit", data: data_attributes)
    end


    def human_duration(duration)
      return duration.inspect unless duration.is_a?(ActiveSupport::Duration)

      # taken and modified from ActiveSupport::Duration#inspect version 4.2.6
      duration.parts.
        reduce(::Hash.new(0)) { |h,(l,r)| h[l] += r; h }.
        sort_by {|unit,  _ | [:years, :months, :days, :minutes, :seconds].index(unit)}.
        map     {|unit, val| "#{val} #{val == 1 ? t(unit, scope: 'dunlop.duration', default: unit.to_s.chop) : t(unit, scope: 'dunlop.duration.plural', default: unit.to_s)}"}.
        to_sentence(locale: ::I18n.locale)
    end


    def render_as_dunlop_modal(partial_name, options={})
      render "dunlop/workflow_step/modal_renderer", partial_name: partial_name, options: options
    end

    def dunlop_class_ability(permission, klass, options={})
      user = options[:user] || @user
      check_box_tag "user[role_names][]", "#{permission}-class-#{klass.name}", user.role_names.include?("#{permission}-class-#{klass.name}"), id: "role-#{klass.name.underscore.parameterize}"
    end

    def dunlop_ability(permission, type, target, options={})
      user = options[:user] || @user
      authorization = [permission, type, target].join('-')
      check_box_tag "user[role_names][]", authorization, user.role_names.include?(authorization), id: "role-#{authorization}"
    end

    def tarray(array, options={})
      array.map do |entry|
        if entry.respond_to?(:model_name)
          if can?(:read, entry)
            [entry.model_name.human, entry]
          end
        else
          [entry, entry]
        end
      end.compact
    end

    def link_to_model(model)
      return nil unless model.present?
      return nil unless can?(:read, model)
      class_base = model.class.name.deconstantize
      name = model.try(:presentation_name) || model.try(:model_name).try(:human) || model.class.name
      if %w[SourceFile ExecutionBatch].include?(class_base)
        path = dunlop.polymorphic_path(model.becomes(class_base.constantize)) rescue nil
      else
        path = main_app.polymorphic_path(model) rescue nil
        #TODO: handle becomes?
      end
      return model.try(:presentation_name) unless path.present?
      link_to name, path
    end
  end
end
