# typed: strict
# frozen_string_literal: true

module Tapioca
  module Commands
    class CheckShims < Command
      extend T::Sig
      include SorbetHelper
      include RBIFilesHelper

      sig do
        params(
          gem_rbi_dir: String,
          dsl_rbi_dir: String,
          annotations_rbi_dir: String,
          shim_rbi_dir: String,
          todo_rbi_file: String,
          payload: T::Boolean,
          number_of_workers: T.nilable(Integer)
        ).void
      end
      def initialize(
        gem_rbi_dir:,
        dsl_rbi_dir:,
        annotations_rbi_dir:,
        shim_rbi_dir:,
        todo_rbi_file:,
        payload:,
        number_of_workers:
      )
        super()
        @gem_rbi_dir = gem_rbi_dir
        @dsl_rbi_dir = dsl_rbi_dir
        @annotations_rbi_dir = annotations_rbi_dir
        @shim_rbi_dir = shim_rbi_dir
        @todo_rbi_file = todo_rbi_file
        @payload = payload
        @number_of_workers = number_of_workers
      end

      sig { override.void }
      def execute
        index = RBI::Index.new

        if (!Dir.exist?(@shim_rbi_dir) || Dir.empty?(@shim_rbi_dir)) && !File.exist?(@todo_rbi_file)
          say("No shim RBIs to check", :green)

          return
        end

        payload_path = T.let(nil, T.nilable(String))

        if @payload
          if sorbet_supports?(:print_payload_sources)
            Dir.mktmpdir do |dir|
              payload_path = dir
              result = sorbet("--no-config --print=payload-sources:#{payload_path}")

              unless result.status
                raise Thor::Error, <<~ERROR
                  "Sorbet failed to dump payload"
                  #{result.err}
                ERROR
              end

              index_rbis(index, "payload", payload_path, number_of_workers: @number_of_workers)
            end
          else
            raise Thor::Error, <<~ERROR
              The version of Sorbet used in your Gemfile.lock does not support `--print=payload-sources`
              Current: v#{SORBET_GEM_SPEC.version}
              Required: #{FEATURE_REQUIREMENTS[:print_payload_sources]}
            ERROR
          end
        end

        index_rbi(index, "todo", @todo_rbi_file)
        index_rbis(index, "shim", @shim_rbi_dir, number_of_workers: @number_of_workers)
        index_rbis(index, "gem", @gem_rbi_dir, number_of_workers: @number_of_workers)
        index_rbis(index, "dsl", @dsl_rbi_dir, number_of_workers: @number_of_workers)
        index_rbis(index, "annotation", @annotations_rbi_dir, number_of_workers: @number_of_workers)

        duplicates = duplicated_nodes_from_index(index, shim_rbi_dir: @shim_rbi_dir, todo_rbi_file: @todo_rbi_file)

        unless duplicates.empty?
          messages = []

          duplicates.each do |key, nodes|
            messages << set_color("\nDuplicated RBI for #{key}:", :red)

            nodes.each do |node|
              node_loc = node.loc

              next unless node_loc

              loc_string = location_to_payload_url(node_loc, path_prefix: payload_path)
              messages << set_color(" * #{loc_string}", :red)
            end
          end

          messages << set_color(
            "\nPlease remove the duplicated definitions from #{@shim_rbi_dir} and #{@todo_rbi_file}", :red
          )

          raise Thor::Error, messages.join("\n")
        end

        say("\nNo duplicates found in shim RBIs", :green)
      end
    end
  end
end