require 'json'
require 'net/http'
require 'uri'


module Youtube
  class ApiClient
    ENDPOINT = 'https://www.googleapis.com/youtube/v3'

    def initialize api_key: ENV.fetch('YOUTUBE_API_KEY')
      @api_key = api_key
    end

    def search_videos q:, published_after: nil, published_before: nil, page_token: nil
      get_json('/search', {
          part:           'snippet',
          type:           'video',
          q:,
          order:          'date',
          maxResults:     50,
          regionCode:     'JP',
          relevanceLanguage: 'ja',
          publishedAfter: published_after&.iso8601,
          publishedBefore: published_before&.iso8601,
          pageToken:      page_token }.compact)
    end

    def videos ids
      return { 'items' => [] } if ids.empty?

      get_json('/videos', part: 'snippet,status,contentDetails', id: ids.join(','))
    end

    def playlist_items playlist_id:, page_token: nil
      get_json('/playlistItems', {
          part:       'snippet,contentDetails,status',
          playlistId: playlist_id,
          maxResults: 50,
          pageToken:  page_token }.compact)
    end

    def channel id: nil, handle: nil
      raise ArgumentError, 'id or handle is required' if id.present? == handle.present?

      params = { part: 'snippet,contentDetails' }
      params[:id] = id if id.present?
      params[:forHandle] = handle if handle.present?

      get_json('/channels', params)
    end

    private

    def get_json path, params
      uri = URI(ENDPOINT + path)
      uri.query = URI.encode_www_form(params.merge(key: @api_key))

      response = Net::HTTP.start(uri.host,
                                 uri.port,
                                 use_ssl: true,
                                 open_timeout: 10,
                                 read_timeout: 30) do |http|
        http.get(uri)
      end

      unless response.is_a?(Net::HTTPSuccess)
        raise "YouTube API error: #{ response.code } #{ response.body }"
      end

      JSON.parse(response.body)
    end
  end
end
