# frozen_string_literal: true

## --- BEGIN LICENSE BLOCK ---
# Original work Copyright (c) 2015-present the fastlane authors
# Modified work Copyright 2019-present WeWantToKnow AS
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
## --- END LICENSE BLOCK ---

require_relative 'changelog'
require_relative '../ui/ui'
require_relative '../../u3d/utils'

module U3dCore
  # Verifies the user runs the latest version of this gem
  class UpdateChecker
    def self.start_looking_for_update(gem_name)
      return if Helper.test?
      return if U3dCore::Env.truthy?("U3D_SKIP_UPDATE_CHECK")

      @start_time = Time.now

      Thread.new do
        server_results[gem_name] = fetch_latest(gem_name)
      rescue StandardError
        # we don't want to show a stack trace if something goes wrong
      end
    end

    def self.server_results
      @server_results ||= {}
    end

    class << self
      attr_reader :start_time
    end

    def self.update_available?(gem_name, current_version)
      latest = server_results[gem_name]
      return (latest && (Gem::Version.new(latest) > Gem::Version.new(current_version)))
    end

    # wait a abit for results when commands run real quick
    def self.wait_for_results
      sleep([0, 0.4 - (Time.now - @start_time)].max) if @start_time
    end

    def self.show_update_status(gem_name, current_version)
      wait_for_results unless update_available?(gem_name, current_version)
      show_update_message(gem_name, current_version) if update_available?(gem_name, current_version)
    end

    # Show a message to the user to update to a new version of u3d
    # Use this method, as this will detect the current Ruby environment and show an
    # appropriate message to the user
    def self.show_update_message(gem_name, current_version)
      available = server_results[gem_name]
      puts("")
      puts('#######################################################################')
      if available
        puts("# #{gem_name} #{available} is available. You are on #{current_version}.")
      else
        puts("# An update for #{gem_name} is available. You are on #{current_version}.")
      end
      puts("# You should use the latest version.")
      puts("# Please update using `#{update_command(gem_name)}`.")

      # this could be fetched from the gem
      puts("# To see what's new, open https://github.com/DragonBox/#{gem_name}/releases.") if U3dCore::Env.truthy?("U3D_HIDE_CHANGELOG")

      if !Helper.bundler? && Random.rand(5) == 1
        # We want to show this message from time to time, if the user doesn't use bundler
        puts('#######################################################################')
        puts("# Run `sudo gem cleanup` from time to time to speed up u3d")
      end
      puts('#######################################################################')
      Changelog.show_changes(gem_name, current_version, update_gem_command: UpdateChecker.update_command(gem_name)) unless U3dCore::Env.truthy?("U3D_HIDE_CHANGELOG")

      ensure_rubygems_source
    end

    # The command that the user should use to update the gem
    def self.update_command(gem_name)
      if Helper.bundler?
        "bundle update #{gem_name.downcase}"
      else
        "sudo gem install #{gem_name.downcase}"
      end
    end

    # Check if RubyGems is set as a gem source
    # on some machines that might not be the case
    # and then users can't find the update when
    # running the specified command
    def self.ensure_rubygems_source
      return if `gem sources`.include?("https://rubygems.org")

      puts("")
      UI.error("RubyGems is not listed as your Gem source")
      UI.error("You can run `gem sources` to see all your sources")
      UI.error("Please run the following command to fix this:")
      UI.command("gem sources --add https://rubygems.org")
    end

    def self.fetch_latest(gem_name)
      JSON.parse(U3d::Utils.page_content(generate_fetch_url(gem_name)))["version"]
    end

    def self.generate_fetch_url(gem_name)
      "https://rubygems.org/api/v1/gems/#{gem_name}.json"
    end
  end
end
