require 'miq_bulk_import'

class ConfigurationController < ApplicationController
  include Mixins::StartUrl
  include Mixins::GenericSessionMixin
  include Mixins::BreadcrumbsMixin

  logo_dir = File.expand_path(Rails.root.join('public', 'upload'))
  Dir.mkdir(logo_dir) unless File.exist?(logo_dir)

  VIEW_RESOURCES = DEFAULT_SETTINGS[:views].keys.each_with_object({}) { |value, acc| acc[value.to_s] = value }.freeze

  before_action :check_privileges
  before_action :get_session_data
  after_action :cleanup_action
  after_action :set_session_data

  def title
    _("My Settings")
  end

  def index
    assert_privileges('my_settings_view')
    @breadcrumbs = []
    active_tab = nil
    if role_allows?(:feature => "my_settings_visuals")
      active_tab = 1 if active_tab.nil?
    elsif role_allows?(:feature => "my_settings_default_filters")
      active_tab = 3 if active_tab.nil?
    elsif role_allows?(:feature => "my_settings_time_profiles")
      active_tab = 4 if active_tab.nil?
    end
    @tabform = params[:load_edit_err] ? @tabform : "ui_#{active_tab}"
    tab_vars(active_tab)
    edit
    render :action => "show"
  end

  # handle buttons pressed on the button bar
  def button
    @refresh_div = "main_div" # Default div for button.rjs to refresh
    timeprofile_delete if params[:pressed] == "tp_delete"
    copy_record if params[:pressed] == "tp_copy"
    edit_record if params[:pressed] == "tp_edit"

    if !@refresh_partial && @flash_array.nil? # if no button handler ran, show not implemented msg
      add_flash(_("Button not yet implemented"), :error)
      @refresh_partial = "layouts/flash_msg"
      @refresh_div = "flash_msg_div"
    end

    if params[:pressed].ends_with?("_edit", "_copy")
      javascript_redirect(:action => @refresh_partial, :id => @redirect_id)
    else
      build_tabs
      render :update do |page|
        page << javascript_prologue
        page.replace("flash_msg_div", :partial => "layouts/flash_msg")
        page << "miqScrollTop();" if @flash_array.present?
        page.replace_html("main_div", :partial => "ui_4") # Replace the main div area contents
        page << javascript_reload_toolbars
      end
    end
  end

  def edit
    set_form_vars # Go fetch the settings into the object for the form
    session[:changed] = @changed = false
    build_tabs
  end

  # New tab was pressed
  def change_tab
    assert_privileges('my_settings_view')
    tab_vars(params['uib-tab'])
    @tabform = "ui_" + params['uib-tab'] if params['uib-tab'] != "5"
    edit
    render :action => "show"
  end

  # AJAX driven routine to check for changes in ANY field on the user form
  def filters_field_changed
    assert_privileges('my_settings_default_filters')
    return unless load_edit("config_edit__ui3", "configuration")

    id = params[:id].split('-').last.to_i
    @edit[:new].find { |x| x[:id] == id }[:search_key] = params[:check] == '1' ? nil : '_hidden_'
    @edit[:current].each_with_index do |arr, i| # needed to compare each array element's attributes to find out if something has changed
      next if @edit[:new][i][:search_key] == arr[:search_key]

      @changed = true
      break
    end
    @changed ||= false
    render :update do |page|
      page << javascript_prologue
      page << javascript_for_miq_button_visibility(@changed)
    end
  end

  def update
    assert_privileges('my_settings_default_filters')
    tab_vars(@tabform.split('_').last)
    if params["save"]
      case @tabform
      when "ui_3" # User Filters tab
        @edit = session[:edit]
        @edit[:new].each do |filter|
          search = MiqSearch.find(filter[:id])
          search.update(:search_key => filter[:search_key]) unless search.search_key == filter[:search_key]
        end
        add_flash(_("Default Filters saved successfully"))
        edit
        render :action => "show"
        return # No config file for Visuals yet, just return
      end
    elsif params["reset"]
      edit
      add_flash(_("All changes have been reset"), :warning)
      render :action => "show"
    end
  end

  # Show the users list
  def show_timeprofiles
    build_tabs if params[:action] == "change_tab" || %w[cancel add save].include?(params[:button])
    @timeprofiles = if report_admin_user?
                      TimeProfile.in_my_region.ordered_by_desc
                    else
                      TimeProfile.in_my_region.for_user(session[:userid]).ordered_by_desc
                    end
    timeprofile_set_days_hours
    @initial_table_data = table_data
    drop_breadcrumb(:name => _("Time Profiles"), :url => "/configuration/change_tab/?tab=4")
  end

  def timeprofile_set_days_hours(_timeprofile = @timeprofile)
    @timeprofile_details = {}
    @timeprofiles.each do |timeprofile|
      @timeprofile_details[timeprofile.description] = {}
      profile_key = timeprofile.profile[:days].nil? ? "days" : :days
      @timeprofile_details[timeprofile.description][:days] =
        timeprofile.profile[profile_key].collect { |day| DateTime::ABBR_DAYNAMES[day.to_i] }
      profile_key = timeprofile.profile[:hours].nil? ? "hours" : :hours
      @timeprofile_details[timeprofile.description][:hours] = []
      temp_arr = timeprofile.profile[profile_key].collect(&:to_i).sort
      st = ""
      temp_arr.each_with_index do |hr, i|
        if hr.to_i + 1 == temp_arr[i + 1]
          st = "#{get_hr_str(hr).split('-').first}-" if st == ""
        else
          hours = st == '' ? get_hr_str(hr) : st + get_hr_str(hr).split('-').last
          @timeprofile_details[timeprofile.description][:hours].push(hours)
          st = ""
        end
      end
      if @timeprofile_details[timeprofile.description][:hours].length > 1 &&
         @timeprofile_details[timeprofile.description][:hours].first.split('-').first == "12AM" &&
         @timeprofile_details[timeprofile.description][:hours].last.split('-').last == "12AM"
        # manipulating midnight hours to be displayed on show screen
        @timeprofile_details[timeprofile.description][:hours][0] =
          @timeprofile_details[timeprofile.description][:hours].last.split('-').first + '-' +
          @timeprofile_details[timeprofile.description][:hours].first.split('-').last
        @timeprofile_details[timeprofile.description][:hours].delete_at(@timeprofile_details[timeprofile.description][:hours].length - 1)
      end
      @timeprofile_details[timeprofile.description][:tz] = if timeprofile.profile[:tz].nil?
                                                             timeprofile.profile["tz"]
                                                           else
                                                             timeprofile.profile[:tz]
                                                           end
    end
  end

  def get_hr_str(hr)
    hours = (1..12).to_a
    hour = hr.to_i
    case hour
    when 0..10  then from = to = "AM"
    when 11     then from, to = %w[AM PM]
    when 12..22 then from = to = "PM"
    else             from, to = %w[PM AM]
    end
    hour = hour >= 12 ? hour - 12 : hour
    "#{hours[hour - 1]}#{from}-#{hours[hour]}#{to}"
  end

  def timeprofile_new
    assert_privileges("my_settings_time_profiles")
    @all_timezones = ActiveSupport::TimeZone.all.collect { |tz| ["(GMT#{tz.formatted_offset}) #{tz.name}", tz.name] }.freeze
    @timeprofile = TimeProfile.new
    @timeprofile_action = "timeprofile_new"
    @userid = session[:userid]
    @in_a_form = true
    @breadcrumbs = []
    drop_breadcrumb(:name => _("Add new Time Profile"), :url => "/configuration/timeprofile_edit")
    render :action => "timeprofile_edit"
  end

  def timeprofile_edit
    assert_privileges("my_settings_time_profiles")
    @all_timezones = ActiveSupport::TimeZone.all.collect { |tz| ["(GMT#{tz.formatted_offset}) #{tz.name}", tz.name] }.freeze
    @timeprofile = TimeProfile.find(params[:id])
    @timeprofile_action = "timeprofile_edit"
    @initial_reports_table_data = reports_table_data

    if @timeprofile.profile_type == "global" && !report_admin_user?
      @tp_restricted = true
      title = _("Time Profile")
    else
      title = _("Edit")
    end

    add_flash(_("Global Time Profile cannot be edited")) if @timeprofile.profile_type == "global" && !report_admin_user?
    session[:changed] = false
    @userid = session[:userid]
    @in_a_form = true
    drop_breadcrumb(:name => _("%{title} '%{description}'") % {:title       => title,
                                                               :description => @timeprofile.description},
                    :url  => "/configuration/timeprofile_edit")
  end

  # Delete all selected or single displayed VM(s)
  def timeprofile_delete
    assert_privileges("my_settings_time_profiles")
    timeprofiles = []
    unless params[:id] # showing a list, scan all selected timeprofiles
      timeprofiles = find_checked_items
      if timeprofiles.empty?
        add_flash(_("No Time Profiles were selected for deletion"), :error)
      else
        selected_timeprofiles = TimeProfile.where(:id => timeprofiles)
        selected_timeprofiles.each do |tp|
          if tp.description == "UTC"
            timeprofiles.delete(tp.id.to_s)
            add_flash(_("Default Time Profile \"%{name}\" cannot be deleted") % {:name => tp.description}, :error)
          elsif tp.profile_type == "global" && !report_admin_user?
            timeprofiles.delete(tp.id.to_s)
            add_flash(_("\"%{name}\": Global Time Profiles cannot be deleted") % {:name => tp.description}, :error)
          elsif !tp.miq_reports.empty?
            timeprofiles.delete(tp.id.to_s)
            add_flash(n_("\"%{name}\": In use by %{rep_count} Report, cannot be deleted",
                         "\"%{name}\": In use by %{rep_count} Reports, cannot be deleted",
                         tp.miq_reports.count) % {:name => tp.description, :rep_count => tp.miq_reports.count}, :error)
          end
        end
      end
      process_timeprofiles(timeprofiles, "destroy") unless timeprofiles.empty?
    end
    show_timeprofiles
  end

  def timeprofile_copy
    assert_privileges("my_settings_time_profiles")
    session[:set_copy] = "copy"
    @all_timezones = ActiveSupport::TimeZone.all.collect { |tz| ["(GMT#{tz.formatted_offset}) #{tz.name}", tz.name] }.freeze
    @in_a_form = true
    @timeprofile = TimeProfile.find(params[:id])
    @timeprofile_action = "timeprofile_copy"
    session[:changed] = false
    @userid = session[:userid]
    drop_breadcrumb(:name => _("Adding copy of '%{description}'") % {:description => @timeprofile.description},
                    :url  => "/configuration/timeprofile_edit")
    render :action => "timeprofile_edit"
  end

  def show
    show_timeprofiles if params[:typ] == "timeprofiles"
  end

  def self.session_key_prefix
    "configuration"
  end

  private

  def table_data
    rows = []
    @timeprofiles.each do |timeprofile|
      cells = []
      row = {}
      row[:clickId] = timeprofile.id.to_s
      row[:clickable] = true
      row[:id] = timeprofile.id.to_s
      cells.push({:is_checkbox => true})
      cells.push({:text => timeprofile.description})
      cells.push({:text => timeprofile.profile_type})
      cells.push({:text => timeprofile.profile_key})
      cells.push({:text => @timeprofile_details[timeprofile.description][:days].join(", ")})
      cells.push({:text => @timeprofile_details[timeprofile.description][:hours].join(", ")})
      cells.push({:text => @timeprofile_details[timeprofile.description][:tz]})
      cells.push({:text => timeprofile.rollup_daily_metrics.to_s.capitalize})
      row[:cells] = cells
      rows.push(row)
    end
    rows
  end

  def reports_table_data
    rows = []
    @timeprofile.miq_reports.sort_by { |a| a.name.downcase }.each do |report|
      cells = []
      row = {}
      row[:clickable] = false
      row[:id] = report.id.to_s
      cells.push({:text => report.name, :icon => 'fa fa-file-text-o'})
      cells.push({:text => report.title})
      row[:cells] = cells
      rows.push(row)
    end
    rows
  end

  # copy single selected Object
  def edit_record
    obj = find_checked_items
    @refresh_partial = "timeprofile_edit"
    @redirect_id = obj[0]
  end

  # copy single selected Object
  def copy_record
    obj = find_checked_items
    @refresh_partial = "timeprofile_copy"
    @redirect_id = obj[0]
  end

  def build_tabs
    @breadcrumbs = []
    if @tabform != "ui_4"
      drop_breadcrumb({:name => _("User Interface Configuration"), :url => "/configuration/edit"}, true)
    end

    @active_tab = @tabform.split("_").last
    @labels = [_("Visual"), _("Default Filters"), _("Time Profiles")]
    @tabs = []
    @tabs.push(["1", _("Visual")])          if role_allows?(:feature => "my_settings_visuals")
    @tabs.push(["3", _("Default Filters")]) if role_allows?(:feature => "my_settings_default_filters")
    @tabs.push(["4", _("Time Profiles")])   if role_allows?(:feature => "my_settings_time_profiles")
  end

  def set_form_vars
    case @tabform
    when 'ui_1'
      @edit = {
        :current => {},
        :key     => 'config_edit__ui1',
      }
    when 'ui_3'
      filters = MiqSearch.where(:search_type => "default")
      current = filters.map do |filter|
        {:id => filter.id, :search_key => filter.search_key}
      end
      @edit = {
        :key         => 'config_edit__ui3',
        :set_filters => true,
        :current     => current,
      }
      @df_tree = TreeBuilderDefaultFilters.new(:df_tree, @sb, true, :data => filters)
      self.x_active_tree = :df_tree
    when 'ui_4'
      @edit = {
        :current => {},
        :key     => 'config_edit__ui4',
      }
      show_timeprofiles
    else
      @edit = {
        :current => {},
        :key     => '',
      }
    end
    @edit[:new] = copy_hash(@edit[:current])
    session[:edit] = @edit
  end

  def get_session_data
    super
    @tabform      = session[:config_tabform]    if session[:config_tabform]
    @schema_ver   = session[:config_schema_ver] if session[:config_schema_ver]
    @zone_options = session[:zone_options]      if session[:zone_options]
  end

  def set_session_data
    super
    session[:config_tabform]    = @tabform
    session[:config_schema_ver] = @schema_ver
    session[:vm_filters]        = @filters
    session[:vm_catinfo]        = @catinfo
    session[:zone_options]      = @zone_options
  end

  def tab_vars(current_tab)
    @path = '/configuration/change_tab/'
    @current_tab = current_tab.to_s
    @check_for_changes = true
  end

  def merge_settings(user_settings, global_settings)
    prune_old_settings(user_settings ? user_settings.merge(global_settings) : global_settings)
  end

  # typically passing in session, but sometimes passing in @session
  def prune_old_settings(s)
    # ui_1
    s[:display].delete(:pres_mode)          # :pres_mode replaced by :theme
    s.delete(:css)                          # Moved this to @css
    s.delete(:adv_search)                   # These got in around sprint 40 by accident
    s[:display].delete(:vmcompare)          # :vmcompare moved to :views hash
    s[:display].delete(:vm_summary_cool)    # :vm_summary_cool moved to :views hash
    s[:views].delete(:vm_summary_cool)      # :views/:vm_summary_cool changed to :dashboards
    s[:views].delete(:dashboards)           # :dashboards is obsolete now

    s
  end

  def breadcrumbs_options
    {
      :breadcrumbs => [
        {:title => _("My Settings")},
      ],
    }
  end

  menu_section :set
end
