class SavedSearch < ActiveRecord::Base
  UNCATEGORIZED_NAME = "uncategorized"

  module ListbooruMethods
    extend ActiveSupport::Concern

    module ClassMethods
      def enabled?
        Danbooru.config.aws_sqs_saved_search_url.present?
      end

      def posts_search_available?
        enabled? && CurrentUser.is_gold?
      end

      def sqs_service
        SqsService.new(Danbooru.config.aws_sqs_saved_search_url)
      end

      def refresh_listbooru(user_id)
        return false unless enabled?

        sqs_service.send_message("refresh\n#{user_id}")
      end

      def reset_listbooru(user_id)
        return false unless enabled?

        user = User.find(user_id)

        sqs_service.send_message("delete\n#{user_id}\nall\n")

        user.saved_searches.each do |saved_search|
          sqs_service.send_message("create\n#{user_id}\n#{saved_search.category}\n#{saved_search.tag_query}", :delay_seconds => 30)
        end

        true
      end

      def rename_listbooru(user_id, old_category, new_category)
        return false unless enabled?

        sqs_service.send_message("rename\n#{user_id}\n#{old_category}\n#{new_category}\n")

        true
      end

      def post_ids(user_id, name = nil)
        return [] unless enabled?

        if name
          hash_name = Cache.hash(name)
        else
          hash_name = nil
        end

        body = Cache.get("ss-pids-#{user_id}-#{hash_name}", 60) do
          params = {
            "key" => Danbooru.config.listbooru_auth_key,
            "user_id" => user_id
          }

          if name == UNCATEGORIZED_NAME
            params["name"] = nil
          elsif name.present?
            params["name"] = name
          end

          uri = URI.parse("#{Danbooru.config.listbooru_server}/users")
          uri.query = URI.encode_www_form(params)

          Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.is_a?(URI::HTTPS)) do |http|
            resp = http.request_get(uri.request_uri)
            if resp.is_a?(Net::HTTPSuccess)
              resp.body
            else
              raise "HTTP error code: #{resp.code} #{resp.message}"
            end
          end
        end

        body.to_s.scan(/\d+/).map(&:to_i)
      end
    end

    def update_listbooru_on_create
      return unless SavedSearch.enabled?
      return unless user.is_gold?

      SavedSearch.sqs_service.send_message("create\n#{user_id}\n#{category}\n#{tag_query}")
    end

    def update_listbooru_on_destroy
      return unless SavedSearch.enabled?

      SavedSearch.sqs_service.send_message("delete\n#{user_id}\n#{category}\n#{tag_query}")
    end

    def update_listbooru_on_update
      return unless SavedSearch.enabled?
      return unless user.is_gold?

      SavedSearch.sqs_service.send_message("update\n#{user_id}\n#{category_was}\n#{tag_query_was}\n#{category}\n#{tag_query}")
    end
  end

  include ListbooruMethods

  belongs_to :user
  validates :tag_query, :presence => true
  validate :validate_count
  attr_accessible :tag_query, :category
  before_create :update_user_on_create
  before_update :update_listbooru_on_update
  after_destroy :update_user_on_destroy
  after_create :update_listbooru_on_create
  after_destroy :update_listbooru_on_destroy
  validates_uniqueness_of :tag_query, :scope => :user_id
  before_validation :normalize

  def self.tagged(tags)
    where(:tag_query => normalize(tags)).first
  end

  def self.normalize(tag_query)
    Tag.scan_query(tag_query).join(" ")
  end

  def self.normalize_category(category)
    category.to_s.strip.gsub(/\s+/, "_").downcase
  end

  def self.rename(user_id, old_category, new_category)
    user = User.find(user_id)
    old_category = normalize_category(old_category)
    new_category = normalize_category(new_category)
    user.saved_searches.where(category: old_category).update_all(category: new_category)
    rename_listbooru(user_id, old_category, new_category)
  end

  def self.categories_for(user)
    user.saved_searches.pluck("distinct category").map do |x|
      if x.blank?
        SavedSearch::UNCATEGORIZED_NAME
      else
        x
      end
    end
  end

  def normalize
    self.category = SavedSearch.normalize_category(category) if category
    self.tag_query = SavedSearch.normalize(tag_query)
  end

  def validate_count
    if user.saved_searches.count + 1 > user.max_saved_searches
      self.errors[:user] << "can only have up to #{user.max_saved_searches} " + "saved search".pluralize(user.max_saved_searches)
    end
  end

  def update_user_on_create
    if !user.has_saved_searches?
      user.update_attribute(:has_saved_searches, true)
    end
  end

  def update_user_on_destroy
    if user.saved_searches.count == 0
      user.update_attribute(:has_saved_searches, false)
    end
  end

  def tag_query_array
    Tag.scan_tags(tag_query)
  end
end
