# typed: false
require "rails_helper"

RSpec.describe Domain::Post::FaPost do
  describe "validations" do
    let(:post) { build(:domain_post_fa_post) }

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

    it "validates state inclusion" do
      expect do post.state = "invalid" end.to raise_error(ArgumentError)
      %w[ok removed scan_error file_error].each do |valid_state|
        post.state = valid_state
        expect(post).to be_valid
      end
    end

    it "defaults state to 'ok'" do
      new_post = described_class.new
      expect(new_post.state).to eq("ok")
    end
  end

  describe "creators" do
    it "works" do
      post = create(:domain_post_fa_post)
      user = create(:domain_user_fa_user)
      post.creator = user
      expect(post.creator).to eq(user)

      expect(post.user_post_creations.count).to eq(1)
      expect(post.user_post_creations.first.user).to eq(user)
    end
  end

  describe "files" do
    it "works" do
      post = create(:domain_post_fa_post)
      file = create(:domain_post_file, post: post)
      expect(post.file).to eq(file)

      expect(Domain::PostFile.where(post: post).count).to eq(1)
      expect(Domain::PostFile.where(post: post).first).to eq(file)
    end
  end

  describe "attributes" do
    let(:post) { build(:domain_post_fa_post) }
    let(:time) { Time.now }

    it "can be initialized by fa_id" do
      post = described_class.new(fa_id: 123)
      expect(post).to be_valid
      expect(post.fa_id).to eq(123)
      expect(post.state).to eq("ok")
      expect(post.save).to be_truthy
    end

    it "handles basic attributes" do
      post.category = "artwork"
      post.theme = "fantasy"
      post.species = "dragon"
      post.gender = "male"
      post.description = "A cool description"
      post.num_favorites = 42
      post.num_comments = 10
      post.num_views = 100

      expect(post.category).to eq("artwork")
      expect(post.theme).to eq("fantasy")
      expect(post.species).to eq("dragon")
      expect(post.gender).to eq("male")
      expect(post.description).to eq("A cool description")
      expect(post.num_favorites).to eq(42)
      expect(post.num_comments).to eq(10)
      expect(post.num_views).to eq(100)
    end

    it "handles array attributes" do
      keywords = %w[dragon fantasy digital]
      post.keywords = keywords
      expect(post.keywords).to eq(keywords)
    end

    it "handles datetime attributes" do
      post.posted_at = time
      post.scanned_at = time

      expect(post.posted_at).to be_within(1.second).of(time)
      expect(post.scanned_at).to be_within(1.second).of(time)
    end

    it "defaults keywords to empty array" do
      new_post = described_class.new
      expect(new_post.keywords).to eq([])
    end

    it "can be selected by an attribute" do
      post = create(:domain_post_fa_post)
      query = described_class.where(fa_id: post.fa_id)
      expect(query.count).to eq(1)
      query =
        described_class.select(:fa_id, :json_attributes).where(
          fa_id: post.fa_id,
        )
      expect(query.map(&:fa_id)).to eq([post.fa_id])

      query = described_class.pluck(:id, :fa_id)
      expect(query).to eq([[post.id, post.fa_id]])
    end

    it "can be ordered by an attribute" do
      create(:domain_post_fa_post, fa_id: 1)
      create(:domain_post_fa_post, fa_id: 2)

      query =
        described_class.select(:fa_id, :json_attributes).order(fa_id: :asc)
      expect(query.map(&:fa_id)).to eq([1, 2])

      query = described_class.order(fa_id: :desc)
      expect(query.map(&:fa_id)).to eq([2, 1])
    end
  end

  describe "factory" do
    it "works" do
      post = create(:domain_post_fa_post)
      expect(post).to be_valid
      expect(post.type).to eq("Domain::Post::FaPost")
    end

    it "works with traits" do
      post = create(:domain_post_fa_post, :removed)
      expect(post).to be_valid
      expect(post.state).to eq("removed")
    end
  end
end
