# typed: strict
module Domain
  module VisualSearchHelper
    extend T::Sig

    # Calculate the similarity percentage between two fingerprint hash values
    # @param hash_value [String] The hash value to compare
    # @param reference_hash_value [String] The reference hash value to compare against
    # @return [Float] The similarity percentage between 0 and 100
    sig do
      params(hash_value: String, reference_hash_value: String).returns(Float)
    end
    def calculate_similarity_percentage(hash_value, reference_hash_value)
      # Calculate hamming distance between the two hash values
      distance =
        DHashVips::IDHash.distance(
          hash_value.to_i(2),
          reference_hash_value.to_i(2),
        )

      max_distance = 256
      # # Calculate similarity percentage based on distance
      ((max_distance - distance) / max_distance.to_f * 100).round(1).clamp(
        0,
        100,
      )
    end

    # Determine the background color class based on similarity percentage
    # @param similarity_percentage [Float] The similarity percentage between 0 and 100
    # @return [String] The Tailwind CSS background color class
    sig { params(similarity_percentage: Float).returns(String) }
    def match_badge_bg_color(similarity_percentage)
      case similarity_percentage
      when 90..100
        "bg-green-600"
      when 70..89
        "bg-blue-600"
      when 50..69
        "bg-amber-500"
      else
        "bg-slate-700"
      end
    end

    # Determine the text color class based on similarity percentage
    # @param similarity_percentage [Float] The similarity percentage between 0 and 100
    # @return [String] The Tailwind CSS text color class
    sig { params(similarity_percentage: Float).returns(String) }
    def match_text_color(similarity_percentage)
      case similarity_percentage
      when 90..100
        "text-green-700"
      when 70..89
        "text-blue-700"
      when 50..69
        "text-amber-700"
      else
        "text-slate-700"
      end
    end

    # Get the CSS classes for the match percentage badge
    # @param similarity_percentage [Float] The similarity percentage between 0 and 100
    # @return [String] The complete CSS classes for the match percentage badge
    sig { params(similarity_percentage: Float).returns(String) }
    def match_badge_classes(similarity_percentage)
      "#{match_badge_bg_color(similarity_percentage)} text-white text-xs rounded-full px-3 py-1 shadow-md"
    end

    class SimilarFingerprintResult < T::Struct
      const :fingerprint, Domain::PostFile::BitFingerprint
      const :similarity_percentage, Float
    end

    # Find similar images based on the fingerprint
    sig do
      params(
        fingerprint_value: String,
        fingerprint_detail_value: String,
        limit: Integer,
        oversearch: Integer,
      ).returns(T::Array[SimilarFingerprintResult])
    end
    def find_similar_fingerprints(
      fingerprint_value:,
      fingerprint_detail_value:,
      limit: 32,
      oversearch: 2
    )
      ActiveRecord::Base.connection.execute("SET ivfflat.probes = 10")

      Domain::PostFile::BitFingerprint
        .order(
          Arel.sql "(fingerprint_value <~> '#{ActiveRecord::Base.connection.quote_string(fingerprint_value)}')"
        )
        .limit(limit * oversearch)
        .to_a
        .uniq(&:post_file_id)
        .map do |other_fingerprint|
          SimilarFingerprintResult.new(
            fingerprint: other_fingerprint,
            similarity_percentage:
              calculate_similarity_percentage(
                fingerprint_detail_value,
                T.must(other_fingerprint.fingerprint_detail_value),
              ),
          )
        end
        .sort { |a, b| b.similarity_percentage <=> a.similarity_percentage }
        .take(limit)
    end
  end
end
