require 'rails_helper'

RSpec.describe "Settings", type: :request do
  let(:user) { create :user, cn: 'mark', ou: 'kosmos.org' }
  let(:other_user) { create :user, id: 2, cn: 'markymark', ou: 'kosmos.org', email: 'markymark@interscope.com' }
  let(:auth_event) { JSON.parse(File.read("#{Rails.root}/spec/fixtures/nostr/valid_auth_event.json")) }

  before do
    login_as user, :scope => :user

    allow_any_instance_of(User).to receive(:dn)
      .and_return("cn=#{user.cn},ou=kosmos.org,cn=users,dc=kosmos,dc=org")
    allow_any_instance_of(User).to receive(:nostr_pubkey).and_return(nil)

    allow(LdapManager::FetchUserByNostrKey).to receive(:call).with(
      pubkey: "07e188a1ff87ce171d517b8ed2bb7a31b1d3453a0db3b15379ec07b724d232f3"
    ).and_return(nil)
  end

  describe "GET /settings/nostr" do
    it "works" do
      get setting_path(:nostr)
      expect(response).to have_http_status(200)
    end
  end

  describe "POST /settings/set_nostr_pubkey" do
    before do
      session_stub = { shared_secret: "YMeTyOxIEJcfe6vd" }
      allow_any_instance_of(SettingsController).to receive(:session).and_return(session_stub)
    end

    context "With valid data" do
      before do
        expect(LdapManager::UpdateNostrKey).to receive(:call).with(
          dn: "cn=mark,ou=kosmos.org,cn=users,dc=kosmos,dc=org",
          pubkey: "07e188a1ff87ce171d517b8ed2bb7a31b1d3453a0db3b15379ec07b724d232f3"
        ).and_return(0)

        post set_nostr_pubkey_settings_path,
          params: { signed_event: auth_event }.to_json,
          headers: {
            "CONTENT_TYPE" => "application/json",
            "HTTP_ACCEPT" => "application/json"
          }
      end

      it "returns a success status" do
        expect(response).to have_http_status(200)
      end

      it "informs the user about the success" do
        expect(flash[:success]).to eq("Public key verification successful")
      end
    end

    context "With key already in use by someone else" do
      before do
        expect(LdapManager::FetchUserByNostrKey).to receive(:call).with(
          pubkey: "07e188a1ff87ce171d517b8ed2bb7a31b1d3453a0db3b15379ec07b724d232f3"
        ).and_return(other_user)
        expect(LdapManager::UpdateNostrKey).not_to receive(:call)

        post set_nostr_pubkey_settings_path,
          params: { signed_event: auth_event }.to_json,
          headers: {
            "CONTENT_TYPE" => "application/json",
            "HTTP_ACCEPT" => "application/json"
          }
      end

      it "returns a 422 status" do
        expect(response).to have_http_status(422)
      end

      it "informs the user about the failure" do
        expect(flash[:alert]).to eq("Public key already in use for a different account")
      end
    end

    context "With wrong site tag" do
      before do
        Setting.accounts_domain = "accounts.wikipedia.org"
        expect(LdapManager::UpdateNostrKey).not_to receive(:call)

        post set_nostr_pubkey_settings_path,
          params: { signed_event: auth_event }.to_json,
          headers: {
            "CONTENT_TYPE" => "application/json",
            "HTTP_ACCEPT" => "application/json"
          }
      end

      after do
        Setting.accounts_domain = "accounts.kosmos.org"
      end

      it "returns a 422 status" do
        expect(response).to have_http_status(422)
      end

      it "informs the user about the failure" do
        expect(flash[:alert]).to eq("Public key could not be verified")
      end
    end

    context "With wrong shared secret" do
      before do
        session_stub = { shared_secret: "ho-chi-minh" }
        allow_any_instance_of(SettingsController).to receive(:session).and_return(session_stub)

        expect(LdapManager::UpdateNostrKey).not_to receive(:call)

        post set_nostr_pubkey_settings_path,
          params: { signed_event: auth_event }.to_json,
          headers: {
            "CONTENT_TYPE" => "application/json",
            "HTTP_ACCEPT" => "application/json"
          }
      end

      it "returns a 422 status" do
        expect(response).to have_http_status(422)
      end

      it "informs the user about the failure" do
        expect(flash[:alert]).to eq("Public key could not be verified")
      end
    end
  end
end
