# typed: false
require "rails_helper"

RSpec.describe Domain::User::FaUser, type: :model do
  describe "validations" do
    let(:user) { build(:domain_user_fa_user) }

    it "is valid with valid attributes" do
      expect(user).to be_valid
    end

    it "requires name" do
      user.name = nil
      expect(user).not_to be_valid
      expect(user.errors[:name]).to include("can't be blank")
    end

    it "requires url_name" do
      user.url_name = nil
      expect(user).not_to be_valid
      expect(user.errors[:url_name]).to include("can't be blank")
    end
  end

  describe "#to_param" do
    let(:user) { build(:domain_user_fa_user, url_name: "artist123") }

    it "returns nil when url_name is blank" do
      user.url_name = nil
      expect(user.to_param).to be_nil

      user.url_name = ""
      expect(user.to_param).to be_nil
    end

    it "returns fa/url_name when url_name is present" do
      expect(user.to_param).to eq("fa@artist123")
    end
  end

  describe "associations" do
    let(:user) { create(:domain_user_fa_user) }
    let!(:post1) { create(:domain_post_fa_post) }
    let!(:post2) { create(:domain_post_fa_post) }
    let!(:post3) { create(:domain_post_fa_post) }
    let!(:faved_post1) { create(:domain_post_fa_post) }
    let!(:faved_post2) { create(:domain_post_fa_post) }
    let!(:unfaved_post) { create(:domain_post_fa_post) }

    before do
      # Create user_post_creations to associate posts with user
      Domain::UserPostCreation.create!(user: user, post: post1)
      Domain::UserPostCreation.create!(user: user, post: post2)

      # Create user_post_favs to associate faved posts with user
      Domain::UserPostFav::FaUserPostFav.create!(user: user, post: faved_post1)
      Domain::UserPostFav::FaUserPostFav.create!(user: user, post: faved_post2)
    end

    describe "#posts" do
      it "returns associated FA posts" do
        expect(user.posts).to match_array([post1, post2])
        expect(user.posts).not_to include(post3)
      end

      it "returns posts of correct type" do
        expect(user.posts).to all(be_a(Domain::Post::FaPost))
      end
    end

    describe "#faved_posts" do
      it "returns faved FA posts" do
        expect(user.faved_posts).to match_array([faved_post1, faved_post2])
        expect(user.faved_posts).not_to include(unfaved_post)
      end

      it "returns posts of correct type" do
        expect(user.faved_posts).to all(be_a(Domain::Post::FaPost))
      end

      it "keeps posts and faved posts separate" do
        expect(user.faved_posts).not_to include(post1, post2)
        expect(user.posts).not_to include(faved_post1, faved_post2)
      end
    end

    describe "#user_search_names" do
      let(:user) do
        create(
          :domain_user_fa_user,
          name: "name_attr",
          url_name: "url_name_attr",
          full_name: "artist name",
        )
      end

      it "returns associated user search names" do
        user.reload
        expect(user.user_search_names.map(&:name)).to match_array(
          ["name_attr", "url_name_attr", "artist name"],
        )
      end

      it "changes search names when name changes" do
        user.name = "new_name"
        user.save!
        user.reload
        expect(user.user_search_names.map(&:name)).to match_array(
          ["artist name", "new_name", "url_name_attr"],
        )
      end
    end
  end

  describe "favs_scans" do
    let(:user) { create(:domain_user_fa_user) }
    let(:log_entry1) { create(:http_log_entry, requested_at: 2.days.ago) }
    let(:log_entry2) { create(:http_log_entry, requested_at: 1.day.ago) }

    it "creates a favs scan" do
      create(
        :domain_user_job_event_add_tracked_object,
        :favs_scan,
        user:,
        log_entry: log_entry1,
      )
      create(
        :domain_user_job_event_add_tracked_object,
        :favs_scan,
        user:,
        log_entry: log_entry2,
      )

      # test ordered by requested_at
      expect(user.favs_scans.count).to eq(2)
      expect(user.favs_scans.map(&:log_entry)).to eq([log_entry1, log_entry2])

      # test aggregation methods
      expect(user.favs_scans.maximum(:requested_at)).to be_within(1.second).of(
        log_entry2.requested_at,
      )
      expect(user.favs_scans.minimum(:requested_at)).to be_within(1.second).of(
        log_entry1.requested_at,
      )
    end
  end
end
