require 'rails_helper'

RSpec.describe 'Collection Job Accessories API', type: :request do
  let(:user) { create(:user) }
  let(:other_user) { create(:user) }
  let(:access_token) do
    Doorkeeper::AccessToken.create!(resource_owner_id: user.id, expires_in: 30.days, scopes: 'public')
  end
  let(:headers) do
    { 'Authorization' => "Bearer #{access_token.token}", 'Content-Type' => 'application/json' }
  end

  let(:job) { create(:job) }
  let(:job_accessory) { create(:job_accessory, job: job) }

  describe 'GET /api/v1/collection/job_accessories' do
    let(:job1) { create(:job) }
    let(:job2) { create(:job) }
    let(:job_accessory1) { create(:job_accessory, job: job1) }
    let(:job_accessory2) { create(:job_accessory, job: job2) }
    let!(:collection_accessory1) { create(:collection_job_accessory, user: user, job_accessory: job_accessory1) }
    let!(:collection_accessory2) { create(:collection_job_accessory, user: user, job_accessory: job_accessory2) }
    let!(:other_user_accessory) { create(:collection_job_accessory, user: other_user) }

    it 'returns the current user\'s collection job accessories' do
      get '/api/v1/collection/job_accessories', headers: headers

      expect(response).to have_http_status(:ok)
      json = JSON.parse(response.body)
      expect(json['collection_job_accessories'].length).to eq(2)
    end

    it 'supports filtering by job' do
      get '/api/v1/collection/job_accessories', params: { job_id: job1.id }, headers: headers

      expect(response).to have_http_status(:ok)
      json = JSON.parse(response.body)
      accessories = json['collection_job_accessories']
      expect(accessories.length).to eq(1)
      expect(accessories.first['job_accessory']['job']['id']).to eq(job1.id)
    end

    it 'returns unauthorized without authentication' do
      get '/api/v1/collection/job_accessories'
      expect(response).to have_http_status(:unauthorized)
    end
  end

  describe 'GET /api/v1/collection/job_accessories/:id' do
    let!(:collection_accessory) { create(:collection_job_accessory, user: user, job_accessory: job_accessory) }

    it 'returns the collection job accessory' do
      get "/api/v1/collection/job_accessories/#{collection_accessory.id}", headers: headers

      expect(response).to have_http_status(:ok)
      json = JSON.parse(response.body)
      expect(json['id']).to eq(collection_accessory.id)
      expect(json['job_accessory']['id']).to eq(job_accessory.id)
    end

    it 'returns not found for other user\'s job accessory' do
      other_collection = create(:collection_job_accessory, user: other_user)
      get "/api/v1/collection/job_accessories/#{other_collection.id}", headers: headers

      expect(response).to have_http_status(:not_found)
    end

    it 'returns not found for non-existent job accessory' do
      get "/api/v1/collection/job_accessories/#{SecureRandom.uuid}", headers: headers

      expect(response).to have_http_status(:not_found)
    end

    it 'returns unauthorized without authentication' do
      get "/api/v1/collection/job_accessories/#{collection_accessory.id}"
      expect(response).to have_http_status(:unauthorized)
    end
  end

  describe 'POST /api/v1/collection/job_accessories' do
    let(:valid_attributes) do
      {
        collection_job_accessory: {
          job_accessory_id: job_accessory.id
        }
      }
    end

    it 'creates a new collection job accessory' do
      expect do
        post '/api/v1/collection/job_accessories', params: valid_attributes.to_json, headers: headers
      end.to change(CollectionJobAccessory, :count).by(1)

      expect(response).to have_http_status(:created)
      json = JSON.parse(response.body)
      expect(json['job_accessory']['id']).to eq(job_accessory.id)
    end

    it 'returns error when job accessory already in collection' do
      create(:collection_job_accessory, user: user, job_accessory: job_accessory)

      post '/api/v1/collection/job_accessories', params: valid_attributes.to_json, headers: headers

      expect(response).to have_http_status(:conflict)
      json = JSON.parse(response.body)
      expect(json['error']['message']).to include('already exists in your collection')
    end

    it 'returns error for non-existent job accessory' do
      invalid_attributes = {
        collection_job_accessory: {
          job_accessory_id: SecureRandom.uuid
        }
      }

      post '/api/v1/collection/job_accessories', params: invalid_attributes.to_json, headers: headers

      expect(response).to have_http_status(:unprocessable_entity)
    end
  end

  describe 'DELETE /api/v1/collection/job_accessories/:id' do
    let!(:collection_accessory) { create(:collection_job_accessory, user: user, job_accessory: job_accessory) }

    it 'deletes the collection job accessory' do
      expect do
        delete "/api/v1/collection/job_accessories/#{collection_accessory.id}", headers: headers
      end.to change(CollectionJobAccessory, :count).by(-1)

      expect(response).to have_http_status(:no_content)
    end

    it 'returns not found for other user\'s job accessory' do
      other_collection = create(:collection_job_accessory, user: other_user)

      expect do
        delete "/api/v1/collection/job_accessories/#{other_collection.id}", headers: headers
      end.not_to change(CollectionJobAccessory, :count)

      expect(response).to have_http_status(:not_found)
    end

    it 'returns not found for non-existent job accessory' do
      delete "/api/v1/collection/job_accessories/#{SecureRandom.uuid}", headers: headers

      expect(response).to have_http_status(:not_found)
    end
  end
end