# typed: false
# frozen_string_literal: true

require "jwt"
require "openssl"
require "httpsensible"

class Object
  # Relies on the fix implemented in https://github.com/rails/rails/pull/39966 to ensure
  # that blank values don't result in queries with empty values, eg. `?filter[metadata]=`, when
  # we prefer (and accept!) `?filter[metadata]`.
  def to_query(key)
    blank? ? CGI.escape(key.to_param).to_s : "#{CGI.escape(key.to_param)}=#{CGI.escape(to_param.to_s)}"
  end
end

module Hephaestus
  class YettoService
    # Version is set by the consuming plug
    YETTO_API_VERSION_TLD = "#{Hephaestus::PROTOCOL}#{Hephaestus::YETTO_API_URL}/#{Rails.configuration.yetto_api_version}"

    class << self
      def yetto_client
        @yetto_client ||= Httpsensible::Client.new(user_agent: "#{Rails.application.class.module_parent.name}/#{Hephaestus::Engine::GIT_SHA}")
      end

      def encoded_jwt
        Httpsensible::JWT.encode_jwt(Hephaestus::YETTO_PLUG_PEM, Hephaestus::YETTO_PLUG_ID)
      end

      def perform_token_exchange(plug_installation_id)
        response = yetto_client.with_headers({ "Authorization" => "Bearer #{encoded_jwt}" }).post("#{YETTO_API_VERSION_TLD}/plug/installations/#{plug_installation_id}/access_tokens")
        body = response.parsed_json_body
        body["token"]
      end

      def get_plug_installation(plug_installation_id)
        token = perform_token_exchange(plug_installation_id)
        yetto_client.with_headers({ "Authorization" => "Bearer #{token}" }).get("#{YETTO_API_VERSION_TLD}/installations/#{plug_installation_id}")
      end

      def update_plug_installation(plug_installation_id, params)
        plug_installation = {}

        plug_installation[:settings] = params.fetch(:settings, {})
        plug_installation[:credentials] = params.fetch(:credentials, {})

        token = perform_token_exchange(plug_installation_id)
        yetto_client.with_headers({ "Authorization" => "Bearer #{token}" }).patch("#{YETTO_API_VERSION_TLD}/installations/#{plug_installation_id}", json: plug_installation)
      end

      def get_messages_in_inbox(plug_installation_id, inbox_id, filter: {})
        token = perform_token_exchange(plug_installation_id)

        yetto_client.with_headers({ "Authorization" => "Bearer #{token}" }).get("#{YETTO_API_VERSION_TLD}/inboxes/#{inbox_id}/messages#{to_filter_query(filter)}")
      end

      def get_messages_in_conversation(plug_installation_id, conversation_id, filter: {})
        token = perform_token_exchange(plug_installation_id)

        yetto_client.with_headers("Authorization" => "Bearer #{token}").get("#{YETTO_API_VERSION_TLD}/conversations/#{conversation_id}/messages#{to_filter_query(filter)}")
      end

      def update_message(plug_installation_id, message_id, params)
        token = perform_token_exchange(plug_installation_id)

        yetto_client.with_headers("Authorization" => "Bearer #{token}").patch("#{YETTO_API_VERSION_TLD}/messages/#{message_id}", json: params)
      end

      def create_conversation(plug_installation_id, inbox_id, params)
        token = perform_token_exchange(plug_installation_id)

        yetto_client.with_headers({ "Authorization" => "Bearer #{token}" }).post("#{YETTO_API_VERSION_TLD}/inboxes/#{inbox_id}/conversations", json: params)
      end

      def create_message_reply(plug_installation_id, message_id, params)
        token = perform_token_exchange(plug_installation_id)

        yetto_client.with_headers("Authorization" => "Bearer #{token}").post("#{YETTO_API_VERSION_TLD}/messages/#{message_id}/replies", json: params)
      end

      def add_message_to_conversation(plug_installation_id, conversation_id, params)
        token = perform_token_exchange(plug_installation_id)

        yetto_client.with_headers({ "Authorization" => "Bearer #{token}" }).post("#{YETTO_API_VERSION_TLD}/conversations/#{conversation_id}/messages", json: params)
      end

      def get_plug_installations(filter: {})
        yetto_client.with_headers({ "Authorization" => "Bearer #{encoded_jwt}" }).get("#{YETTO_API_VERSION_TLD}/plug/installations#{to_filter_query(filter)}")
      end

      private def to_filter_query(hash)
        return "" if hash.nil?

        "?#{hash.to_query("filter")}"
      end
    end
  end
end