class EasyPageZoneModule < ActiveRecord::Base
  include EasyUtils::BlockUtils
  include Redmine::I18n

  include Redmine::SafeAttributes
  safe_attributes 'tab_id',
    'tab',
    'settings',
    'position',
    'entity_id',
    'user_id',
    'easy_page_available_modules_id',
    'easy_page_available_zones_id',
    'easy_pages_id'

  self.primary_key = 'uuid'

  belongs_to :page_definition, :class_name => 'EasyPage', :foreign_key => 'easy_pages_id'
  belongs_to :available_zone, :class_name => 'EasyPageAvailableZone', :foreign_key => 'easy_page_available_zones_id'
  belongs_to :available_module, :class_name => 'EasyPageAvailableModule', :foreign_key => 'easy_page_available_modules_id'
  belongs_to :user, :class_name => 'User', :foreign_key => 'user_id'
  has_one :zone_definition, :class_name => 'EasyPageZone', :through => :available_zone
  has_one :module_definition, :class_name => 'EasyPageModule', :through => :available_module

  validates_presence_of :easy_pages_id, :easy_page_available_zones_id, :easy_page_available_modules_id

  attr_protected :uuid

  acts_as_positioned

  store :settings, coder: JSON

  attr_accessor :css_class

  before_save :generate_module_uuid

  def self.delete_modules(easy_page, user_id = nil, entity_id = nil, tab_id = nil)
    return unless easy_page.is_a?(EasyPage)

    epzm_scope = EasyPageZoneModule.where(:easy_pages_id => easy_page.id, :user_id => user_id.presence, :entity_id => entity_id.presence)
    epzm_scope = epzm_scope.where(:tab_id => tab_id) if tab_id

    epzm_scope.delete_all

    if !tab_id.nil? && EasyPageUserTab.table_exists?
      EasyPageUserTab.destroy(tab_id)
    end
  end

  def self.create_from_page_template(page_template, user_id = nil, entity_id = nil)
    return unless page_template.is_a?(EasyPageTemplate)

    easy_page = page_template.page_definition

    EasyPageZoneModule.delete_modules(easy_page, user_id, entity_id)

    EasyPageUserTab.where(page_id: easy_page.id, user_id: user_id, entity_id: entity_id).destroy_all

    tab_id_mapping = {}
    new_tabs = []

    if EasyPageTemplateTab.table_exists?
      EasyPageTemplateTab.page_template_tabs(page_template, nil).each do |page_template_tab|
        page_tab = EasyPageUserTab.new(page_id: easy_page.id, user_id: user_id, entity_id: entity_id, name: page_template_tab.name, settings: page_template_tab.settings)
        page_tab.save!
        new_tabs << page_tab
        tab_id_mapping[page_template_tab.id] = page_tab.id
      end
    end

    module_ids_mapping = {}

    EasyPageTemplateModule.where(easy_page_templates_id: page_template.id).order(:easy_page_available_zones_id, :position).all.each do |template_module|
      if EasyPageUserTab.table_exists?
        page_module = EasyPageZoneModule.new(easy_pages_id: easy_page.id, easy_page_available_zones_id: template_module.easy_page_available_zones_id, easy_page_available_modules_id: template_module.easy_page_available_modules_id, user_id: user_id, entity_id: entity_id, position: template_module.position, settings: template_module.settings, tab_id: tab_id_mapping[template_module.tab_id])
      else
        page_module = EasyPageZoneModule.new(easy_pages_id: easy_page.id, easy_page_available_zones_id: template_module.easy_page_available_zones_id, easy_page_available_modules_id: template_module.easy_page_available_modules_id, user_id: user_id, entity_id: entity_id, position: template_module.position, settings: template_module.settings)
      end

      page_module.save!
      module_ids_mapping[template_module.uuid] = page_module.uuid
    end

    # Map tab settings
    new_tabs.each do |tab|
      next if !tab.settings['filters'].is_a?(Array)

      tab.settings['filters'].each do |filter|
        next if !filter['modules'].is_a?(Hash)

        filter['modules'].transform_keys! do |uuid, _|
          module_ids_mapping[uuid]
        end
      end

      tab.save
    end
  end

  # Keep `options` for future.
  # Options:
  #   * query_mapping: for changing old query id in module setting
  def self.clone_by_entity_id(old_entity_id, new_entity_id, options={})
    tab_mapping = {}
    query_mapping = options[:query_mapping] || {}

    EasyPageUserTab.where(:entity_id => old_entity_id).order(:page_id, :position).all.each do |old_tab|
      new_tab = old_tab.dup
      new_tab.entity_id = new_entity_id
      new_tab.save!

      tab_mapping[old_tab.id] = new_tab.id
    end

    EasyPageZoneModule.where(:entity_id => old_entity_id).order(:easy_page_available_zones_id, :position).all.each do |old_page_module|
      new_page_module = old_page_module.dup
      new_page_module.entity_id = new_entity_id
      new_page_module.generate_module_uuid(true)
      new_page_module.tab_id = tab_mapping[old_page_module.tab_id]

      # Map old query_id to new query_id (only for query modules)
      if old_page_module.module_definition.query_module? && (old_query_id = old_page_module.settings[:query_id]) && (new_query_id = query_mapping[old_query_id])
        new_page_module.settings[:query_id] = new_query_id
      end

      new_page_module.save!
    end

  end

  def position_scope
    cond = "#{EasyPageZoneModule.table_name}.easy_pages_id = #{self.easy_pages_id} AND #{EasyPageZoneModule.table_name}.easy_page_available_zones_id = #{self.easy_page_available_zones_id}"
    cond << (self.tab_id.blank? ? " AND #{EasyPageZoneModule.table_name}.tab_id IS NULL" : " AND #{EasyPageZoneModule.table_name}.tab_id = #{self.tab_id}")
    cond << (self.user_id.blank? ? " AND #{EasyPageZoneModule.table_name}.user_id IS NULL" : " AND #{EasyPageZoneModule.table_name}.user_id = #{self.user_id}")
    cond << (self.entity_id.blank? ? " AND #{EasyPageZoneModule.table_name}.entity_id IS NULL" : " AND #{EasyPageZoneModule.table_name}.entity_id = #{self.entity_id}")
    self.class.where(cond)
  end

  def position_scope_was
    cond = "#{EasyPageZoneModule.table_name}.easy_pages_id = #{self.easy_pages_id_was} AND #{EasyPageZoneModule.table_name}.easy_page_available_zones_id = #{self.easy_page_available_zones_id_was}"
    cond << (self.tab_id_was.blank? ? " AND #{EasyPageZoneModule.table_name}.tab_id IS NULL" : " AND #{EasyPageZoneModule.table_name}.tab_id = #{self.tab_id_was}")
    cond << (self.user_id_was.blank? ? " AND #{EasyPageZoneModule.table_name}.user_id IS NULL" : " AND #{EasyPageZoneModule.table_name}.user_id = #{self.user_id_was}")
    cond << (self.entity_id_was.blank? ? " AND #{EasyPageZoneModule.table_name}.entity_id IS NULL" : " AND #{EasyPageZoneModule.table_name}.entity_id = #{self.entity_id_was}")
    self.class.where(cond)
  end

  def generate_module_uuid(force = false)
    if force
      self.uuid = EasyUtils::UUID.generate.dasherize
    else
      self.uuid ||= EasyUtils::UUID.generate.dasherize
    end
  end

  def module_name
    @module_name ||= "#{self.module_definition.module_name.underscore}_#{self.uuid.underscore}"
  end

  def get_settings(params_settings)
    s = default_settings.merge(settings)
    s.merge!(params_settings || {})
    s.delete('user_id')
    s
  end

  # proxy
  def get_show_data(user, params_settings = nil, page_context = {})
    module_definition.page_zone_module = self
    module_definition.get_show_data(get_settings(params_settings), user, page_context || {}) || {}
  end

  # proxy
  def get_edit_data(user, params_settings = nil, page_context = {})
    module_definition.page_zone_module = self
    module_definition.get_edit_data(get_settings(params_settings), user, page_context || {}) || {}
  end

  def floating?
    @floating.nil? ? false : @floating
  end

  def floating=(value)
    @floating = value
  end

  def from_params(params)
    module_definition.before_from_params(self, params)
    write_attribute(:settings, (self.settings || {}).merge(params || {}))
  end

  private

  def default_settings
    {
      'query_type' => '2',
      'query_name' => l('easy_page_module.issue_query.adhoc_query_default_text')
    }
  end

end

