# frozen_string_literal: true

module Decidim
  module DecidimAwesome
    class MenuHacker
      include Decidim::TranslatableAttributes

      def initialize(name, view)
        @name = name
        @organization = view.try(:current_organization)
        @user = view.try(:current_user)
        @view = view
      end

      # returns a combined array of the Decidim defined menu and the hacked stored as config vars
      def items(include_invisible: false)
        return @items if @items

        @items = default_items
        menu_overrides.each do |item|
          default = default_items.find { |i| i.url.gsub(/\?.*/, "") == item.url }
          if default
            item.send("overrided?=", true)
            item[:original_active] = default.active
            @items.reject! { |i| i.url.gsub(/\?.*/, "") == item.url }
          end
          @items << item
        end

        @items.select!(&:visible?) unless include_invisible
        @items.sort_by!(&:position)
      end

      private

      attr_accessor :organization, :user
      attr_reader :name, :view

      def default_items
        @default_items ||= build_menu.items
      end

      def build_menu
        menu = Decidim::Menu.new(name)
        menu.build_for(view)
        menu
      end

      def menu_overrides
        @menu_overrides ||= current_config.map do |item|
          OpenStruct.new(
            label: translated_attribute(item["label"], organization),
            raw_label: item["label"],
            url: item["url"],
            position: item["position"] || 1,
            # see options in https://github.com/comfy/active_link_to
            active: method(:activate?),
            visibility: item["visibility"],
            visible?: visible?(item),
            target: item["target"],
            overrided?: false
          )
        end
      end

      def activate?(url, view)
        urls = @items.map(&:url).sort_by(&:length).reverse
        url == urls.find { |u| view.request.original_fullpath.start_with?(u) }
      end

      def visible?(item)
        case item["visibility"]
        when "hidden"
          false
        when "logged"
          user.present?
        when "non_logged"
          user.blank?
        when "verified_user"
          # the cleaner version should be user.authorizations.any?
          # but there is not relationship between users and authorizations
          Decidim::Authorization.where(user:).any? { |auth| auth.granted? && !auth.expired? }
        else
          true
        end
      end

      def current_config
        @current_config ||= (AwesomeConfig.find_by(var: name, organization:)&.value || []).filter { |i| i.is_a? Hash }
      end
    end
  end
end