require 'rails_helper'

RSpec.describe 'user theme slots', type: :request do
  describe 'GET /users/theme_slots' do
    it 'requires a current user' do
      sign_out

      get '/users/theme_slots'

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

    it 'returns only the current user slots in stable order' do
      user = create(:user)
      other_user = create(:user)
      sign_in_as(user)
      UserThemeSlot.create!(user:, base_theme: 'light', slot_no: 2, tokens: { 'a' => 1 })
      UserThemeSlot.create!(user:, base_theme: 'dark', slot_no: 1, tokens: { 'b' => 2 })
      UserThemeSlot.create!(user: other_user,
                            base_theme: 'dark',
                            slot_no: 3,
                            tokens: { 'c' => 3 })

      get '/users/theme_slots'

      expect(response).to have_http_status(:ok)
      expect(json.map { |slot| [slot.fetch('base_theme'), slot.fetch('slot_no')] }).to eq(
          [['dark', 1], ['light', 2]])
      expect(json.map { |slot| slot.fetch('tokens') }).to eq(
          [{ 'b' => 2 }, { 'a' => 1 }])
    end
  end

  describe 'PUT /users/theme_slots/:base_theme/:slot_no' do
    it 'requires a current user' do
      sign_out

      put '/users/theme_slots/light/1',
          params: { tokens: { background: '0 0% 100%' } },
          as: :json

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

    it 'creates a theme slot' do
      user = create(:user)
      sign_in_as(user)

      expect {
        put '/users/theme_slots/light/1',
            params: { tokens: { background: '0 0% 100%', tagColours: { nico: '#ffffff' } } },
            as: :json
      }.to change(UserThemeSlot, :count).by(1)

      expect(response).to have_http_status(:ok)
      expect(json).to include('base_theme' => 'light', 'slot_no' => 1)
      expect(json.fetch('tokens')).to include(
          'background' => '0 0% 100%',
          'tagColours' => { 'nico' => '#ffffff' })
      expect(user.theme_slots.find_by!(base_theme: 'light', slot_no: 1).tokens).to include(
          'background' => '0 0% 100%')
    end

    it 'updates an existing theme slot instead of creating a duplicate' do
      user = create(:user)
      sign_in_as(user)
      UserThemeSlot.create!(user:, base_theme: 'dark', slot_no: 2, tokens: { 'old' => true })

      expect {
        put '/users/theme_slots/dark/2',
            params: { tokens: { background: '222.2 84% 4.9%' } },
            as: :json
      }.not_to change(UserThemeSlot, :count)

      expect(response).to have_http_status(:ok)
      expect(user.theme_slots.find_by!(base_theme: 'dark', slot_no: 2).tokens).to eq(
          'background' => '222.2 84% 4.9%')
    end

    it 'rejects invalid path parameters and token shapes' do
      sign_in_as(create(:user))

      put '/users/theme_slots/system/4',
          params: { tokens: 'not-object' },
          as: :json

      expect(response).to have_http_status(:unprocessable_entity)
      expect(json.fetch('errors')).to include(
          'base_theme' => ['値が不正です．'])
    end

    it 'rejects non-object tokens for valid slots' do
      sign_in_as(create(:user))

      put '/users/theme_slots/light/1',
          params: { tokens: 'not-object' },
          as: :json

      expect(response).to have_http_status(:unprocessable_entity)
      expect(json.fetch('errors')).to include(
          'tokens' => ['JSON object で指定してください．'])
    end
  end
end
