# typed: true # rubocop:todo Sorbet/StrictSigil
# frozen_string_literal: true

module Homebrew
  module Bundle
    module CaskInstaller
      def self.reset!
        @installed_casks = nil
        @outdated_casks = nil
      end

      private_class_method def self.upgrading?(no_upgrade, name, options)
        return false if no_upgrade
        return true if outdated_casks.include?(name)
        return false unless options[:greedy]

        require "bundle/cask_dumper"
        Homebrew::Bundle::CaskDumper.cask_is_outdated_using_greedy?(name)
      end

      def self.preinstall(name, no_upgrade: false, verbose: false, **options)
        if installed_casks.include?(name) && !upgrading?(no_upgrade, name, options)
          puts "Skipping install of #{name} cask. It is already installed." if verbose
          return false
        end

        true
      end

      def self.install(name, preinstall: true, no_upgrade: false, verbose: false, force: false, **options)
        return true unless preinstall

        full_name = options.fetch(:full_name, name)

        install_result = if installed_casks.include?(name) && upgrading?(no_upgrade, name, options)
          status = "#{options[:greedy] ? "may not be" : "not"} up-to-date"
          puts "Upgrading #{name} cask. It is installed but #{status}." if verbose
          Bundle.brew("upgrade", "--cask", full_name, verbose:)
        else
          args = options.fetch(:args, []).filter_map do |k, v|
            case v
            when TrueClass
              "--#{k}"
            when FalseClass, NilClass
              nil
            else
              "--#{k}=#{v}"
            end
          end

          args << "--force" if force
          args << "--adopt" unless args.include?("--force")
          args.uniq!

          with_args = " with #{args.join(" ")}" if args.present?
          puts "Installing #{name} cask#{with_args}. It is not currently installed." if verbose

          if Bundle.brew("install", "--cask", full_name, *args, verbose:)
            installed_casks << name
            true
          else
            false
          end
        end
        result = install_result

        if cask_installed?(name)
          postinstall_result = postinstall_change_state!(name:, options:, verbose:)
          result &&= postinstall_result
        end

        result
      end

      private_class_method def self.postinstall_change_state!(name:, options:, verbose:)
        postinstall = options.fetch(:postinstall, nil)
        return true if postinstall.blank?

        puts "Running postinstall for #{@name}: #{postinstall}" if verbose
        Kernel.system(postinstall)
      end

      def self.cask_installed_and_up_to_date?(cask, no_upgrade: false)
        return false unless cask_installed?(cask)
        return true if no_upgrade

        !cask_upgradable?(cask)
      end

      def self.cask_in_array?(cask, array)
        return true if array.include?(cask)
        return true if array.include?(cask.split("/").last)

        require "bundle/cask_dumper"
        old_names = Homebrew::Bundle::CaskDumper.cask_oldnames
        old_name = old_names[cask]
        old_name ||= old_names[cask.split("/").last]
        return true if old_name && array.include?(old_name)

        false
      end

      def self.cask_installed?(cask)
        cask_in_array?(cask, installed_casks)
      end

      def self.cask_upgradable?(cask)
        cask_in_array?(cask, outdated_casks)
      end

      def self.installed_casks
        require "bundle/cask_dumper"
        @installed_casks ||= Homebrew::Bundle::CaskDumper.cask_names
      end

      def self.outdated_casks
        require "bundle/cask_dumper"
        @outdated_casks ||= Homebrew::Bundle::CaskDumper.outdated_cask_names
      end
    end
  end
end
