# typed: strict
class HttpLogEntry < ReduxApplicationRecord
  include ImmutableModel
  before_destroy { raise ActiveRecord::ReadOnlyRecord }

  enum :verb, %i[get post], prefix: true
  enum :performed_by,
       %i[direct legacy proxy-1 dedipath-1 direct-gdl serverhost-1],
       prefix: true

  belongs_to :response,
             foreign_key: :response_sha256,
             class_name: "::BlobFile",
             autosave: true

  belongs_to :request_headers, class_name: "::HttpLogEntryHeader"

  belongs_to :response_headers, class_name: "::HttpLogEntryHeader"

  validates :response_sha256, length: { is: 32 }

  belongs_to :caused_by_entry,
             class_name: "::HttpLogEntry",
             foreign_key: :caused_by_id,
             optional: true

  has_many :triggered_entries,
           class_name: "::HttpLogEntry",
           foreign_key: :caused_by_id

  validates_presence_of(
    :uri_scheme,
    :uri_host,
    :uri_path,
    :verb,
    :performed_by,
    :status_code,
    :response_time_ms,
    :content_type,
    :requested_at,
  )

  sig do
    params(uri: T.any(String, Addressable::URI)).returns(
      T.nilable(HttpLogEntry),
    )
  end
  def self.find_by_uri_host_path(uri)
    uri = Addressable::URI.parse(uri) unless uri.is_a?(Addressable::URI)
    where(uri_host: uri.host, uri_path: uri.path).order(
      requested_at: :desc,
    ).first
  end

  sig do
    params(uri: T.any(String, Addressable::URI)).returns(
      T.nilable(HttpLogEntry),
    )
  end
  def self.find_by_uri(uri)
    find_all_by_uri(uri).first
  end

  sig do
    params(uri: T.any(String, Addressable::URI)).returns(
      ::ActiveRecord::Relation,
    )
  end
  def self.find_all_by_uri(uri)
    if uri.is_a?(String) &&
         %w[https:// http:// //].none? { |prefix| uri.start_with?(prefix) }
      uri = "//#{uri}"
    end
    uri = Addressable::URI.parse(uri) unless uri.is_a?(Addressable::URI)
    where(
      uri_host: uri.host,
      uri_path: uri.path,
      uri_query: uri.query,
      uri_hash: uri.fragment,
    ).order(requested_at: :desc)
  end

  sig { returns(T.nilable(Integer)) }
  def response_size
    response&.size_bytes
  end

  sig { returns(T.nilable(String)) }
  def response_bytes
    response&.content_bytes
  end

  sig { params(uri: T.any(String, Addressable::URI)).void }
  def uri=(uri)
    uri = Addressable::URI.parse(uri) if uri.is_a?(String)
    self.uri_scheme = uri.scheme
    self.uri_host = uri.host
    self.uri_path = uri.path
    self.uri_query = uri.query
    self.uri_hash = uri.fragment
  end

  sig { returns(Addressable::URI) }
  def uri
    Addressable::URI.parse(uri_str)
  end

  sig { returns(String) }
  def uri_str
    "#{uri_scheme}://#{uri_host}#{uri_str_without_host}"
  end

  sig { returns(String) }
  def uri_str_without_host
    str = ""
    str += "#{uri_path}"
    str += "?#{uri_query}" if uri_query
    str += "\##{uri_hash}" if uri_hash
    str
  end
end
