module InfinumId
  module Requests
    class InviteSender
      def initialize(resource_id, current_resource_uid)
        @resource = resource_class.find(resource_id)
        @current_resource_uid = current_resource_uid
      end

      def self.call(resource_id, current_resource_uid)
        new(resource_id, current_resource_uid).call
      end

      def call
        send_invite_request
        handle_response
      end

      private

      attr_reader :resource, :current_resource_uid, :response

      def send_invite_request
        @response = HTTP.headers(headers).post(invitation_url, json: invitation_params)
      end

      def handle_response
        case response.code
        when 200
          update_resource
          send_email if InfinumId.infinum_id_send_email
        when 400, 403, 404
          return response.to_s
        when 401..599
          raise response.to_s
        end
      end

      def update_resource
        resource.update(user_params.merge(provider: 'infinum_id'))
        InfinumId::AfterResourceUpdate.call(resource, params[:user])
      end

      def send_email
        params[:invitation_accept_path].blank? ? send_welcome_email : send_invite_email
      end

      def send_invite_email
        InfinumId::Mailer.with(
          resource_id: resource.id, invited_by_uid: current_resource_uid,
          accept_path: params[:invitation_accept_path]
        ).invite_email.deliver_later
      end

      def send_welcome_email
        InfinumId::Mailer.with(
          resource_id: resource.id, invited_by_uid: current_resource_uid
        ).welcome_email.deliver_later
      end

      def params
        @params ||= ActionController::Parameters.new(response.parse)
      end

      def user_params
        params.require(:user).permit(InfinumId.resource_attributes)
      end

      def headers
        {
          client_id: InfinumId.client_id,
          client_secret: InfinumId.client_secret
        }
      end

      def invitation_params
        {
          user: InfinumId::ResourceBlueprint.render_as_json(resource),
          invited_by_uid: current_resource_uid,
          send_invitation: !InfinumId.infinum_id_send_email
        }
      end

      def invitation_url
        "#{InfinumId.url}/api/invitations"
      end

      delegate :resource_name, :resource_class, to: InfinumId
    end
  end
end