# typed: false
require "rails_helper"
describe Domain::Fa::Job::UserAvatarJob do
  let(:user) { create(:domain_user_fa_user, url_name: "meesh", name: "Meesh") }

  let(:http_client_mock) { instance_double("::Scraper::HttpClient") }
  before { Scraper::ClientFactory.http_client_mock = http_client_mock }
  let!(:avatar) do
    create(
      :domain_user_avatar,
      log_entry: nil,
      user: create(:domain_user_fa_user, url_name: "meesh", name: "Meesh"),
    )
  end

  let(:avatar_fixture_file) do
    SpecUtil.read_fixture_file(
      "domain/fa/avatar/meesh_avatar_file.gif",
      mode: "rb",
    )
  end

  let(:avatar_fixture_file_404) do
    SpecUtil.read_fixture_file(
      "domain/fa/avatar/404_avatar_file.gif",
      mode: "rb",
    )
  end

  let(:avatar_fixture_file_2) do
    SpecUtil.read_fixture_file(
      "domain/fa/avatar/roadkillxing_avatar_file.gif",
      mode: "rb",
    )
  end

  shared_context "avatar file found" do
    before do
      @log_entries =
        HttpClientMockHelpers.init_http_client_mock(
          http_client_mock,
          [
            {
              uri: "https://a.furaffinity.net/0/meesh.gif",
              status_code: 200,
              content_type: "image/gif",
              contents: avatar_fixture_file,
            },
          ],
        )
    end
  end

  shared_context "avatar file not found" do
    before do
      @log_entries =
        HttpClientMockHelpers.init_http_client_mock(
          http_client_mock,
          [
            {
              uri: "https://a.furaffinity.net/0/meesh.gif",
              status_code: 404,
              content_type: "image/gif",
              contents: avatar_fixture_file_404,
            },
          ],
        )
    end
  end

  shared_context "avatar file is a server error" do
    before do
      @log_entries =
        HttpClientMockHelpers.init_http_client_mock(
          http_client_mock,
          [
            {
              uri: "https://a.furaffinity.net/0/meesh.gif",
              status_code: 500,
              content_type: "text/html",
              contents: "Server Error",
            },
          ],
        )
    end
  end

  context "the user model exists" do
    context "the server response is 200" do
      include_context "avatar file found"

      it "sets the file and the right state" do
        perform_now({ avatar: })
        avatar.reload
        expect(avatar).not_to be_nil
        expect(avatar.state).to eq("ok")
        expect(avatar.log_entry).to eq(@log_entries[0])
        expect(avatar.downloaded_at).to be_within(3.seconds).of(Time.now)
      end

      context "the avatar model has a file already" do
        it "sets file to the new file" do
          avatar.state = :ok
          first_log_entry =
            create(
              :http_log_entry,
              response:
                create(
                  :blob_file,
                  contents: avatar_fixture_file_2,
                  content_type: "image/gif",
                ),
            )
          avatar.log_entry = first_log_entry
          avatar.save!

          perform_now({ avatar:, force_scan: true })

          avatar.reload
          expect(avatar.state).to eq("ok")
          expect(avatar.log_entry).to eq(@log_entries[0])
          expect(avatar.downloaded_at).to be_within(3.seconds).of(Time.now)
        end
      end
    end

    context "the server response is 404" do
      include_context "avatar file not found"

      it "sets the file and the right state" do
        perform_now({ avatar: })
        avatar.reload
        expect(avatar).not_to be_nil
        expect(avatar.last_log_entry).to eq(@log_entries[0])
        expect(avatar.log_entry).to be_nil
        expect(avatar.downloaded_at).to be_within(3.seconds).of(Time.now)
        expect(avatar.state).to eq("file_404")
      end

      context "a previous successful avatar was downloaded" do
        it "does not overwrite the file" do
          avatar.state = :ok

          log_entry =
            create(
              :http_log_entry,
              response:
                create(
                  :blob_file,
                  contents: avatar_fixture_file,
                  content_type: "image/gif",
                ),
            )
          avatar.log_entry = log_entry
          avatar.last_log_entry = log_entry
          avatar.save!

          perform_now({ avatar:, force_scan: true })

          avatar.reload
          expect(avatar.state).to eq("file_404")
          expect(avatar.log_entry).to eq(log_entry)
          expect(avatar.last_log_entry).to eq(@log_entries[0])
        end
      end
    end

    context "the server response is 500" do
      include_context "avatar file is a server error"

      it "has a file and the right state" do
        expect { perform_now({ avatar: }) }.to raise_error(
          /http 500, log entry.+/,
        )
        avatar.reload
        expect(avatar).not_to be_nil
        expect(avatar.log_entry).to be_nil
        expect(avatar.last_log_entry).to eq(@log_entries[0])
        expect(avatar.state).to eq("http_error")
        expect(avatar.error_message).to eq("http status 500")
      end
    end
  end
end
