# frozen_string_literal: true

require_relative '../../plugin_helper'

describe CustomWizard::Subscription do
  fab!(:user) { Fabricate(:user) }

  it "initializes subscription authentication and subscription" do
    subscription = described_class.new
    expect(subscription.authentication.class).to eq(CustomWizard::Subscription::Authentication)
    expect(subscription.subscription.class).to eq(CustomWizard::Subscription::Subscription)
  end

  it "returns authorized and subscribed states" do
    subscription = described_class.new
    expect(subscription.authorized?).to eq(false)
    expect(subscription.subscribed?).to eq(false)
  end

  context "subscription" do
    before do
      @subscription = described_class.new
    end

    it "updates valid subscriptions" do
      stub_subscription_request(200, valid_subscription)
      expect(@subscription.update).to eq(true)
      expect(@subscription.subscribed?).to eq(true)
    end

    it "handles invalid subscriptions" do
      stub_subscription_request(200, invalid_subscription)
      expect(@subscription.update).to eq(false)
      expect(@subscription.subscribed?).to eq(false)
    end

    it "handles subscription http errors" do
      stub_subscription_request(404, {})
      expect(@subscription.update).to eq(false)
      expect(@subscription.subscribed?).to eq(false)
    end

    it "destroys subscriptions" do
      stub_subscription_request(200, valid_subscription)
      expect(@subscription.update).to eq(true)
      expect(@subscription.destroy_subscription).to eq(true)
      expect(@subscription.subscribed?).to eq(false)
    end

    it "has class aliases" do
      authenticate_subscription
      stub_subscription_request(200, valid_subscription)
      expect(described_class.update).to eq(true)
      expect(described_class.subscribed?).to eq(true)
    end
  end

  context "authentication" do
    before do
      @subscription = described_class.new
      user.update!(admin: true)
    end

    it "generates a valid authentication request url" do
      request_id = SecureRandom.hex(32)
      uri = URI(@subscription.authentication_url(user.id, request_id))
      expect(uri.host).to eq(@subscription.server)

      parsed_query = Rack::Utils.parse_query uri.query
      expect(parsed_query['public_key'].present?).to eq(true)
      expect(parsed_query['nonce'].present?).to eq(true)
      expect(parsed_query['client_id'].present?).to eq(true)
      expect(parsed_query['auth_redirect'].present?).to eq(true)
      expect(parsed_query['application_name']).to eq(SiteSetting.title)
      expect(parsed_query['scopes']).to eq(@subscription.scope)
    end

    def generate_payload(request_id, user_id)
      uri = URI(@subscription.authentication_url(user_id, request_id))
      keys = @subscription.authentication.get_keys(request_id)
      raw_payload = {
        key: "12345",
        nonce: keys.nonce,
        push: false,
        api: UserApiKeysController::AUTH_API_VERSION
      }.to_json
      public_key = OpenSSL::PKey::RSA.new(keys.pem)
      Base64.encode64(public_key.public_encrypt(raw_payload))
    end

    it "handles authentication response if request and response is valid" do
      request_id = SecureRandom.hex(32)
      payload = generate_payload(request_id, user.id)

      expect(@subscription.authentication_response(request_id, payload)).to eq(true)
      expect(@subscription.authorized?).to eq(true)
    end

    it "discards authentication response if user who made request as not an admin" do
      user.update!(admin: false)

      request_id = SecureRandom.hex(32)
      payload = generate_payload(request_id, user.id)

      expect(@subscription.authentication_response(request_id, payload)).to eq(false)
      expect(@subscription.authorized?).to eq(false)
    end

    it "discards authentication response if request_id is invalid" do
      payload = generate_payload(SecureRandom.hex(32), user.id)

      expect(@subscription.authentication_response(SecureRandom.hex(32), payload)).to eq(false)
      expect(@subscription.authorized?).to eq(false)
    end

    it "destroys authentication" do
      request_id = SecureRandom.hex(32)
      payload = generate_payload(request_id, user.id)
      @subscription.authentication_response(request_id, payload)

      expect(@subscription.destroy_authentication).to eq(true)
      expect(@subscription.authorized?).to eq(false)
    end
  end
end