require 'open3'
require 'net/http'
require 'tempfile'

module Geordi
  class ChromedriverUpdater

    def run(options)
      chrome_version = determine_chrome_version
      current_chromedriver_version = determine_chromedriver_version

      latest_chromedriver_version = latest_version(chrome_version)
      if current_chromedriver_version == latest_chromedriver_version
        Interaction.success "No update required: Chromedriver is already on the latest version v#{latest_chromedriver_version}!" unless options[:quiet_if_matching]
      else
        update_chromedriver(latest_chromedriver_version)
      end
    end

    private

    def determine_chrome_version
      stdout_str, _error_str, status = Open3.capture3('google-chrome', '--version')
      chrome_version = unless stdout_str.nil?
        stdout_str[/\AGoogle Chrome ([\d.]+)/, 1]
      end

      if !status.success? || chrome_version.nil?
        Interaction.fail('Could not determine the version of Google Chrome.')
      else
        chrome_version
      end
    end

    def determine_chromedriver_version
      return unless Open3.capture2('which chromedriver')[1].success?

      stdout_str, _error_str, status = Open3.capture3('chromedriver', '-v')
      chromedriver_version = unless stdout_str.nil?
        stdout_str[/\AChromeDriver ([\d.]+)/, 1]
      end

      if !status.success? || chromedriver_version.nil?
        Interaction.fail('Could not determine the version of chromedriver.')
      else
        chromedriver_version
      end
    end

    # Check https://groups.google.com/a/chromium.org/g/chromium-discuss/c/4BB4jmsRyv8/m/TY3FXS4HBgAJ
    # for information how chrome version numbers work
    def major_version(full_version)
      full_version.match(/^(\d+\.\d+\.\d+)\.\d+$/)[1]
    end

    def update_chromedriver(latest_chromedriver_version)
      chromedriver_zip = download_chromedriver(latest_chromedriver_version)

      unzip(chromedriver_zip, File.expand_path('~/bin'))

      # We need to determine the version again, as it could be nil in case no chromedriver was installed before
      Interaction.success "Chromedriver updated to v#{determine_chromedriver_version}."
    end

    def download_chromedriver(latest_version)
      uri = URI("https://chromedriver.storage.googleapis.com/#{latest_version}/chromedriver_linux64.zip")
      response = Net::HTTP.get_response(uri)

      if response.is_a?(Net::HTTPSuccess)
        file = Tempfile.new(['chromedriver', '.zip'])
        file.write(response.body)

        file
      else
        Interaction.fail("Could not download chromedriver v#{latest_version}.")
      end
    end

    def latest_version(chrome_version)
      return @latest_version if @latest_version

      uri = URI("https://chromedriver.storage.googleapis.com/LATEST_RELEASE_#{major_version(chrome_version)}")
      response = Net::HTTP.get_response(uri)

      if response.is_a?(Net::HTTPSuccess)
        @latest_version = response.body.to_s
      else
        Interaction.fail("Could not download the chromedriver v#{chrome_version}.")
      end
    end

    def unzip(zip, output_dir)
      _stdout_str, _error_str, status = Open3.capture3('unzip', '-d', output_dir, '-o', zip.path)

      unless status.success?
        Interaction.fail("Could not unzip #{zip.path}.")
      end
    end
  end
end