require 'rails_helper'

RSpec.describe 'Tag and wiki history integrity', type: :request do
  let(:member_user) { create(:user, role: 'member') }

  def stub_current_user user
    allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(user)
  end

  def create_tag! name:, category: :general
    tag_name = TagName.create!(name:)
    Tag.create!(tag_name:, category:)
  end

  def create_wiki_for_tag! tag:, body: 'wiki body', user: member_user
    Wiki::Commit.create_content!(
        tag_name: tag.tag_name,
        body:,
        created_by_user: user,
        message: 'init')
  end

  before do
    stub_current_user(member_user)
  end

  describe 'PATCH /tags/:id' do
    it 'records wiki_version when tag name changes and tag has wiki' do
      tag = create_tag!(name: 'patch_tag_wiki_before')
      wiki_page = create_wiki_for_tag!(tag:, body: 'wiki body before')

      expect {
        patch "/tags/#{ tag.id }", params: {
          name: 'patch_tag_wiki_after',
        }
      }
          .to change(TagVersion, :count).by(2)
          .and change(WikiVersion, :count).by(1)

      expect(response).to have_http_status(:ok)

      tag.reload
      wiki_page.reload
      version = wiki_page.wiki_versions.order(:version_no).last

      expect(tag.name).to eq('patch_tag_wiki_after')
      expect(wiki_page.title).to eq('patch_tag_wiki_after')

      expect(version).to have_attributes(
        event_type: 'update',
        title: 'patch_tag_wiki_after',
        body: 'wiki body before',
        created_by_user_id: member_user.id
      )
    end

    it 'does not record wiki_version when only category changes' do
      tag = create_tag!(name: 'patch_tag_category_only')
      wiki_page = create_wiki_for_tag!(tag:, body: 'wiki body before')

      before_wiki_versions = wiki_page.wiki_versions.count

      expect {
        patch "/tags/#{ tag.id }", params: {
          category: 'meme',
        }
      }
          .to change(TagVersion, :count).by(2)

      expect(response).to have_http_status(:ok)

      tag.reload
      wiki_page.reload

      expect(tag.name).to eq('patch_tag_category_only')
      expect(tag.category).to eq('meme')
      expect(wiki_page.wiki_versions.count).to eq(before_wiki_versions)
    end
  end

  describe 'PUT /tags/:id' do
    it 'records wiki_version when tag name changes and tag has wiki' do
      tag = create_tag!(name: 'put_tag_wiki_before')
      wiki_page = create_wiki_for_tag!(tag:, body: 'wiki body before')

      expect {
        put "/tags/#{ tag.id }", params: {
          name: 'put_tag_wiki_after',
          category: 'general',
          aliases: '',
          parent_tags: '',
          deprecated: '0',
        }
      }
          .to change(TagVersion, :count).by(2)
          .and change(WikiVersion, :count).by(1)

      expect(response).to have_http_status(:ok)

      tag.reload
      wiki_page.reload
      version = wiki_page.wiki_versions.order(:version_no).last

      expect(tag.name).to eq('put_tag_wiki_after')
      expect(wiki_page.title).to eq('put_tag_wiki_after')

      expect(version).to have_attributes(
        event_type: 'update',
        title: 'put_tag_wiki_after',
        body: 'wiki body before',
        created_by_user_id: member_user.id
      )
    end

    it 'does not record wiki_version when only category changes' do
      tag = create_tag!(name: 'put_tag_category_only')
      wiki_page = create_wiki_for_tag!(tag:, body: 'wiki body before')

      before_wiki_versions = wiki_page.wiki_versions.count

      expect {
        put "/tags/#{ tag.id }", params: {
          name: 'put_tag_category_only',
          category: 'meme',
          aliases: '',
          parent_tags: '',
          deprecated: '0',
        }
      }
          .to change(TagVersion, :count).by(2)

      expect(response).to have_http_status(:ok)

      tag.reload
      wiki_page.reload

      expect(tag.name).to eq('put_tag_category_only')
      expect(tag.category).to eq('meme')
      expect(wiki_page.wiki_versions.count).to eq(before_wiki_versions)
    end

    it 'does not record wiki_version when only aliases change' do
      tag = create_tag!(name: 'put_tag_alias_only')
      wiki_page = create_wiki_for_tag!(tag:, body: 'wiki body before')

      before_wiki_versions = wiki_page.wiki_versions.count

      expect {
        put "/tags/#{ tag.id }", params: {
          name: 'put_tag_alias_only',
          category: 'general',
          aliases: 'put_tag_alias_only_alias',
          parent_tags: '',
          deprecated: '0',
        }
      }
          .to change(TagVersion, :count).by(2)

      expect(response).to have_http_status(:ok)
      expect(wiki_page.reload.wiki_versions.count).to eq(before_wiki_versions)
    end
  end
end
