module EasyPatch
  module ActsAsWatchableInstanceMethodsPatch

    def self.included(base)
      base.send(:include, InstanceMethods)

      base.class_eval do

        alias_method_chain :addable_watcher_users, :easy_extensions
        alias_method_chain :notified_watchers, :easy_extensions
        alias_method_chain :add_watcher, :easy_extensions
        alias_method_chain :remove_watcher, :easy_extensions
        alias_method_chain :watched_by?, :easy_extensions

      end
    end

    module InstanceMethods

      def addable_watcher_users_with_easy_extensions
        return [] if self.project.nil?
        users = self.project.users.with_easy_avatar.visible.sorted
        users = users.where.not(id: self.watcher_user_ids) unless self.new_record?
        if self.is_a?(Issue) && !User.current.allowed_to?(:add_issue_watchers, self.project)
          users.reject! {|user| !self.project.visible?(user)}
        end
        users
      end

      def notified_watchers_with_easy_extensions
        notified = notified_watchers_without_easy_extensions
        notified.reject!{|user| (user.mail_notification == 'only_owner' || user.mail_notification == 'only_assigned')}
        notified
      end

      def add_watcher_with_easy_extensions(user)
        return if self.watchers.detect{|watcher| watcher.user_id == user.id}

        if user.is_a?(Group)
          self.watchers << Watcher.new(:group => user)
        else
          add_watcher_without_easy_extensions(user)
        end
      end

      def remove_watcher_with_easy_extensions(user)
        if user.is_a?(Group)
          users_of_other_watcher_groups = watcher_groups.where.not(:id => user.id).collect{|group| group.users.pluck(:id)}.flatten.uniq
          users_to_remove = [user.id] + user.users.pluck(:id) - users_of_other_watcher_groups

          watchers.where(:user_id => users_to_remove).delete_all
        else
          remove_watcher_without_easy_extensions(user)
        end
      end

      def available_groups
        if self.respond_to?(:project)
          groups = Group.joins(:members).where(:members => { :project_id => self.project_id }).where.not("#{Group.table_name}" => { :id => self.watcher_groups.pluck(:id) }).sorted
          groups = groups.preload(:easy_avatar) if EasySetting.value('avatar_enabled')
        else
          groups = []
        end
        groups
      end

      # Returns true if object is watched by +principal+
      def watched_by_with_easy_extensions?(principal)
        !!(principal && (self.watcher_user_ids.detect {|uid| uid == principal.id } || self.watcher_group_ids.detect {|gid| gid == principal.id }))
      end

    end

  end

  module ActsAsWatchableClassMethodsPatch

    def self.included(base)
      base.class_eval do

        #fix for method safe_attributes= with use mass-assignment
        def acts_as_watchable_with_easy_extensions(options = {})
          acts_as_watchable_without_easy_extensions(options)
          self._protected_attributes[:default].delete 'watcher_user_ids'
          self._protected_attributes[:default].delete 'watcher_ids'

          has_many :watcher_groups, :through => :watchers, :source => :group, :validate => false

        end

        alias_method_chain :acts_as_watchable, :easy_extensions

      end
    end

  end
end
EasyExtensions::PatchManager.register_redmine_plugin_patch 'Redmine::Acts::Watchable::InstanceMethods', 'EasyPatch::ActsAsWatchableInstanceMethodsPatch'
EasyExtensions::PatchManager.register_redmine_plugin_patch 'Redmine::Acts::Watchable::ClassMethods', 'EasyPatch::ActsAsWatchableClassMethodsPatch'
