require './core/base/page_helper'

module PlayerCoreEvents
  # @param url [String] URL to load in manifest area.
  # @return [Boolean] True if event is found within script_timeout, otherwise false
  def has_ready_event?(url)
    ready_event_js =
    "var callback = arguments[arguments.length - 1];
          player.addEventListener(PlayerState.READY, function() { callback(true)});
          player.load('#{url}');"
    TwitchUtils.execute_event_listener_script(ready_event_js, 10)
  end

  # @param url [String] URL to load in manifest area.
  # @param total_count [Fixnum] total number of time to monitor the triggered event
  # @return [Boolean] True if event is found within script_timeout, otherwise false
  def has_metadata_event?(url, total_count = 5)
    metadata_event_js =
    "count = 1;
          var callback = arguments[arguments.length - 1];
          player.addEventListener(window.MetadataEvent.ID3, function() { count++; if(count == #{total_count}) { callback(true)}});
          player.load('#{url}');"
    TwitchUtils.execute_event_listener_script(metadata_event_js, 30)
  end

  # @param stream_url [String] URL to load in manifest area.
  # @return [Boolean] True if stream started and network stats has value.
  def stream_started?(stream_url = "#{VideoPlayerData.player_domain_url}/#{VideoPlayerData.player_channel}")
    stream_started_url =
    "var callback = arguments[arguments.length - 1];
            player.setAdInsertionEnabled(false);
            player.addEventListener(PlayerState.PLAYING, function() { callback(true)});
            player.load('#{stream_url}');
            player.play();"
    TwitchUtils.execute_event_listener_script(stream_started_url, 30)
  end

  # @param stream_url [String] URL to load in manifest area.
  # @param duration [Fixnum] Time to wait for video playback
  # @return [Boolean] True if stream ended.
  def stream_ended?(duration=30)
    stream_ended_js =
    "var callback = arguments[arguments.length - 1];
     player.addEventListener(PlayerState.ENDED, function() { callback(true)});
    "
    TwitchUtils.execute_event_listener_script(stream_ended_js, duration)
  end

  # check video quality for any stream
  # @param quality [string] quality of video (High => 1080p, Medium => 480p, Low => 160p)
  # @param timeout [Integer] Timeout for script
  # @return [Boolean] whether video resolution changed or not
  def set_quality?(quality, timeout = 30)
    # return if already on same quality
    return true if quality == PlayerCore.current_quality['name']
    change_qual_js = "
          var callback = arguments[arguments.length - 1];
          player.addEventListener(PlayerEvent.QUALITY_CHANGED, function(quality) { callback(quality['quality']['name']) });
          all_qualities = player.getQualities();
          for (qual in all_qualities) {
          if (all_qualities[qual]['name'].indexOf('#{quality}') !== -1)
            player.setQuality(all_qualities[qual])
          }"
    # check if QUALITY_CHANGED Event triggered and quality changed correctly
    response = TwitchUtils.execute_event_listener_script(change_qual_js, timeout)
    # In case of IE only true gets returned instead of quality name from callback
    if response.is_a? TrueClass
      return PlayerCore.current_quality['name'].include?(quality)
    end
    return response && response.include?(quality)
  end

  # @param seek_duration [Integer] Seek value for respective button
  # @return [Boolean] True if event is found within script_timeout, otherwise false
  def seek_completed?(seek_duration)
    curr_time = PlayerCore.current_playhead.to_i
    seek_time = (curr_time + seek_duration).to_i
    seek_complete_js = "
          var callback = arguments[arguments.length - 1];
          player.addEventListener(PlayerEvent.SEEK_COMPLETED, function() {
            callback(player.getPosition())
          });
          player.seekTo(#{seek_time})"
    response = TwitchUtils.execute_event_listener_script(seek_complete_js, 20)
    if response.is_a? TrueClass
      expect(PlayerCore.current_playhead).to be >= seek_time
    else
      expect(response.to_i).to eq(seek_time)
    end
  end

  # @return [Boolean] True if event is found within script_timeout, otherwise false
  def last_seek_completed?
    duration  = PlayerCore.stream_duration
    duration1 = (duration / 2).to_i
    duration2 = (duration / 3).to_i
    duration3 = (duration / 4).to_i
    seek_complete_js =
    "var callback = arguments[arguments.length - 1];
          player.addEventListener(PlayerEvent.SEEK_COMPLETED, function(seekedTime) {
            callback(player.getPosition())
            });
            player.seekTo(#{duration1})
            player.seekTo(#{duration2})
            player.seekTo(#{duration3})"
    response = TwitchUtils.execute_event_listener_script(seek_complete_js, 10)
    if response.is_a? TrueClass
      expect(current_playhead).to be_within(3).of(duration3) and expect(response).to be_truthy
    else
      expect(TwitchUtils.execute_event_listener_script(seek_complete_js, 10).to_i).to eq(duration3)
    end
  end

  # @return [Boolean] whether on enabling abs quality changed or not
  def abs_quality_change?
    abs_change_js = "
          var callback = arguments[arguments.length - 1];
          player.addEventListener(PlayerEvent.QUALITY_CHANGED, function() { callback(true) });
          player.setAutoSwitchQuality(true);
          player.seekTo(0)"
    TwitchUtils.execute_event_listener_script(abs_change_js, 30)
  end

  # @param url [String] streaming url to load
  # @return [String]  Error Type
  def check_error(url)
    error_stream =
    "var callback = arguments[arguments.length - 1];
          player.addEventListener(PlayerEvent.ERROR, function(error) {callback(error)});
          player.load('#{url}')"
    TwitchUtils.execute_event_listener_script(error_stream, 10)
  end

  # @param url [String] streaming url to load
  # @return [Array] offline video error data as Hash and time at which event got triggered as Integer
  def tracking_event(url, event_name)
    error_stream =
    "var callback = arguments[arguments.length - 1];
     var result = [];
        player.addEventListener(PlayerEvent.TRACKING, function(spadeData) {
          if (spadeData['name'] == '#{event_name}') {
            result.push(spadeData);
            result.push(parseInt(Date.now() / 1000));
            callback(result)
          }
        });
      player.load('#{url}')"
    TwitchUtils.execute_event_listener_script(error_stream, 30)
  end

  # @param expect_caption [String] Expected Caption
  # @param caption_time [Integer] Time at which caption comes
  # @return [Boolean] True if caption is within given time
  def includes_closed_captions_text?(expect_caption, caption_time)
    cc_stream = "
          var index = 0;
          var callback = arguments[arguments.length - 1];
          player.addEventListener(MetadataEvent.CAPTION, function(caption) {
            index = caption['text'].indexOf('#{expect_caption}');
            if (index !== -1) {
              callback(true)
            }
          });
          player.seekTo(#{caption_time});"
    return TwitchUtils.execute_event_listener_script(cc_stream, 30)
  end

  # Sets quality and then seek to non-buffered region (BufferedDuration + 10 seconds)
  # @param quality [string] quality of video (High => 1080p, Medium => 480p, Low => 160p)
  # @param timeout [Integer] timeout value to wait for SEEK_COMPLETE event, default 30s
  # @return [Boolean] whether video resolution changed or not
  def set_quality_and_seek?(quality, seek_duration, timeout = 30)
    curr_time = PlayerCore.current_playhead
    buffer = PlayerCore.get_buffer_duration
    seek_time = (curr_time + buffer + seek_duration).to_i
    change_qual_js = "
          var res = {}
          var callback = arguments[arguments.length - 1];
          player.addEventListener(PlayerEvent.SEEK_COMPLETED, function() {
            res['position'] = player.getPosition();
            if (Object.keys(res).length == 2) { callback(res) }
          });
          player.addEventListener(PlayerEvent.QUALITY_CHANGED, function(quality) {
            res['quality'] = quality['quality']['name'];
            if (Object.keys(res).length == 2) { callback(res) }
          });
          all_qualities = player.getQualities();
          for (qual in all_qualities) {
            if (all_qualities[qual]['name'].indexOf('#{quality}') !== -1) {
              player.setQuality(all_qualities[qual]);
              player.seekTo(#{seek_time});
            }
         }"
    # check if QUALITY_CHANGED Event triggered and quality changed correctly
    response = TwitchUtils.execute_event_listener_script(change_qual_js, timeout)
    expect(response).not_to be_falsy
    expect(response).to eql({'position' => seek_time, 'quality' => quality})
  end

  # Seeks and then set qaulity to given quality
  # @param quality [string] quality of video (High => 1080p, Medium => 480p, Low => 160p)
  # @param timeout [Integer] timeout value to wait for SEEK_COMPLETE event, default 30s
  # @return [Boolean] whether video resolution changed or not
  def seek_and_set_quality?(quality, seek_duration, timeout = 30)
    curr_time = PlayerCore.current_playhead
    buffer = PlayerCore.get_buffer_duration
    seek_time = (curr_time + buffer + seek_duration).to_i
    change_qual_js = "
        var res = {};
        var callback = arguments[arguments.length - 1];
        player.addEventListener(PlayerEvent.SEEK_COMPLETED, function() {
          res['position'] = player.getPosition();
          if (Object.keys(res).length == 2) { callback(res) }
        });
        player.addEventListener(PlayerEvent.QUALITY_CHANGED, function(quality) {
          res['quality'] = quality['quality']['name'];
          if (Object.keys(res).length == 2) { callback(res) }
        });
        all_qualities = player.getQualities();
        for (qual in all_qualities) {
          if (all_qualities[qual]['name'].indexOf('#{quality}') !== -1) {
            player.seekTo(#{seek_time});
            player.setQuality(all_qualities[qual]);
          }
        }"
    # check if QUALITY_CHANGED Event triggered and quality changed correctly
    response = TwitchUtils.execute_event_listener_script(change_qual_js, timeout)
    expect(response).not_to be_falsy
    expect(response).to eql({'position' => seek_time, 'quality' => quality})
  end

  # Pause stream
  # @return [Boolean] True if player is playing(live/vod) else False
  def pause?
    pause_js =
    "var callback = arguments[arguments.length - 1];
     player.addEventListener(PlayerState.IDLE, function() { callback(true) });
     player.pause();"
    TwitchUtils.execute_event_listener_script(pause_js, 10)
  end

  # Play stream and return current position
  # @return [Boolean/Integer] False if not in playing state else player.getPosition();
  def play
    pause_js =
    "var callback = arguments[arguments.length - 1];
     player.addEventListener(PlayerState.PLAYING, function() {
       callback(player.getPosition())
     });
     player.play();"
    TwitchUtils.execute_event_listener_script(pause_js, 10)
  end

  # @param value [String] buffer event name
  # @return [Hash] event data
  def tracking_event_data(event_name)
    event_data =
    "var callback = arguments[arguments.length - 1];
     player.addEventListener(PlayerEvent.TRACKING, function(spadeData) {
      if ('#{event_name}' == spadeData['name'])
        {callback(spadeData)}
    });"
    TwitchUtils.execute_event_listener_script(event_data, 30)
  end

  # @param url [String] URL to load.
  # @return [Boolean] True if ad started with SPLICE_OUT Event.
  def ad_started?(url)
    ad_start_event =
    "var callback = arguments[arguments.length - 1];
     player.addEventListener(MetadataEvent.SPLICE_OUT, function() { callback(true) });
     player.load('#{url}');
     player.play();"
    TwitchUtils.execute_event_listener_script(ad_start_event, 15)
  end

  # @return [Boolean] True if ad ended with SPLICE_IN Event.
  def ad_ended?
    ad_end_event =
    "var callback = arguments[arguments.length - 1];
     player.addEventListener(MetadataEvent.SPLICE_IN, function() { callback(true) });"
    TwitchUtils.execute_event_listener_script(ad_end_event, 45)
  end
end
