require_relative '../protocol/command_serializer'
require_relative '../protocol/command_deserializer'
require_relative '../handler/handler'
require_relative '../../utils/command'
require_relative '../../utils/command_type'

module Hypertube
  module Core
    module Interpreter
      class Interpreter
        def self.execute(command, connection_data)
          message_byte_array = Hypertube::Core::Protocol::CommandSerializer.serialize(command, connection_data)
          if connection_data.is_a? Utils::WsConnectionData
            require_relative '../web_socket_client/web_socket_client'
            response_byte_array = Hypertube::Core::WebSocketClient::WebSocketClient.send_message(connection_data, message_byte_array)
          elsif connection_data.is_a? Utils::Http2ConnectionData
            require_relative '../http2_client/http2_client'
            response_byte_array = Hypertube::Core::Http2Client::Http2Client.send_message(connection_data, message_byte_array)
          else
            if connection_data.get_headers.length.positive?
              context_metadata_payload = build_context_metadata_payload(command, connection_data)
              command = Hypertube::Utils::Command.new(
                command.runtime_name,
                Hypertube::Utils::CommandType::CONTEXT_METADATA,
                [context_metadata_payload, command]
              )
              message_byte_array = Hypertube::Core::Protocol::CommandSerializer.serialize(command, connection_data)
            end
            if command.runtime_name == Hypertube::Utils::RuntimeNameHt::RUBY && (connection_data.is_a? Utils::InMemoryConnectionData)
              require_relative '../receiver/receiver'
              response_byte_array = Hypertube::Core::Receiver::Receiver.send_command(message_byte_array)[1]
            else
              require_relative '../transmitter/transmitter'
              response_byte_array = Hypertube::Core::Transmitter::Transmitter.send_command(message_byte_array, message_byte_array.length)
            end
          end

          Hypertube::Core::Protocol::CommandDeserializer.new(response_byte_array).deserialize
        end

        def self.process(byte_array)
          received_command = Hypertube::Core::Protocol::CommandDeserializer.new(byte_array).deserialize
          Hypertube::Core::Handler::Handler.handle_command(received_command)
        end

        def self.build_context_metadata_payload(command, connection_data)
          metadata_payload = []
          headers = connection_data.get_headers

          headers.each do |key, value|
            metadata_payload << key
            metadata_payload << value
          end

          Hypertube::Utils::Command.new(command.runtime_name, Hypertube::Utils::CommandType::ARRAY, metadata_payload)
        end
      end
    end
  end
end
