require 'rails_helper'

RSpec.describe Youtube::ApiClient do
  let(:api_key) { 'test-api-key' }
  let(:client) { described_class.new(api_key:) }

  describe '#search_videos' do
    it 'calls YouTube search API with expected params' do
      published_after = Time.zone.parse('2026-05-01 00:00:00')
      published_before = Time.zone.parse('2026-05-02 00:00:00')

      expect(client).to receive(:get_json).with(
        '/search',
        {
          part: 'snippet',
          type: 'video',
          q: 'ぼざろクリーチャー',
          order: 'date',
          maxResults: 50,
          regionCode: 'JP',
          relevanceLanguage: 'ja',
          publishedAfter: published_after.iso8601,
          publishedBefore: published_before.iso8601,
          pageToken: 'NEXT'
        }
      ).and_return({ 'items' => [] })

      client.search_videos(
        q: 'ぼざろクリーチャー',
        published_after:,
        published_before:,
        page_token: 'NEXT'
      )
    end

    it 'omits nil optional params' do
      expect(client).to receive(:get_json).with(
        '/search',
        hash_excluding(:publishedAfter, :publishedBefore, :pageToken)
      ).and_return({ 'items' => [] })

      client.search_videos(q: 'ぼざろクリーチャー')
    end
  end

  describe '#videos' do
    it 'returns empty items when ids are empty' do
      expect(client).not_to receive(:get_json)

      expect(client.videos([])).to eq({ 'items' => [] })
    end

    it 'calls videos API with comma separated ids' do
      expect(client).to receive(:get_json).with(
        '/videos',
        {
          part: 'snippet,status,contentDetails',
          id: 'video-1,video-2'
        }
      ).and_return({ 'items' => [] })

      client.videos(['video-1', 'video-2'])
    end
  end

  describe '#playlist_items' do
    it 'calls playlistItems API with page token' do
      expect(client).to receive(:get_json).with(
        '/playlistItems',
        {
          part: 'snippet,contentDetails,status',
          playlistId: 'PL123',
          maxResults: 50,
          pageToken: 'NEXT'
        }
      ).and_return({ 'items' => [] })

      client.playlist_items(playlist_id: 'PL123', page_token: 'NEXT')
    end

    it 'omits page token when nil' do
      expect(client).to receive(:get_json).with(
        '/playlistItems',
        {
          part: 'snippet,contentDetails,status',
          playlistId: 'PL123',
          maxResults: 50
        }
      ).and_return({ 'items' => [] })

      client.playlist_items(playlist_id: 'PL123')
    end
  end

  describe '#channel' do
    it 'calls channels API by id' do
      expect(client).to receive(:get_json).with(
        '/channels',
        {
          part: 'snippet,contentDetails',
          id: 'UC123'
        }
      ).and_return({ 'items' => [] })

      client.channel(id: 'UC123')
    end

    it 'calls channels API by handle' do
      expect(client).to receive(:get_json).with(
        '/channels',
        {
          part: 'snippet,contentDetails',
          forHandle: '@some_handle'
        }
      ).and_return({ 'items' => [] })

      client.channel(handle: '@some_handle')
    end

    it 'raises when neither id nor handle is given' do
      expect { client.channel }.to raise_error(ArgumentError, 'id or handle is required')
    end

    it 'raises when both id and handle are given' do
      expect do
        client.channel(id: 'UC123', handle: '@some_handle')
      end.to raise_error(ArgumentError, 'id or handle is required')
    end
  end
end
