# typed: strict
# frozen_string_literal: true

module CodeOwnership
  module Private
    #
    # This class is responsible for turning CodeOwnership directives (e.g. annotations, package owners)
    # into a GitHub CODEOWNERS file, as specified here:
    # https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
    #
    class CodeownersFile
      extend T::Sig

      sig { returns(T::Array[String]) }
      def self.actual_contents_lines
        if !path.exist?
          [""]
        else
          content = path.read
          lines = path.read.split("\n")
          if content.end_with?("\n")
            lines << ""
          end
          lines
        end
      end

      sig { returns(T::Array[T.nilable(String)]) }
      def self.expected_contents_lines
        cache = Private.glob_cache.raw_cache_contents

        header = <<~HEADER
          # STOP! - DO NOT EDIT THIS FILE MANUALLY
          # This file was automatically generated by "bin/codeownership validate".
          #
          # CODEOWNERS is used for GitHub to suggest code/file owners to various GitHub
          # teams. This is useful when developers create Pull Requests since the
          # code/file owner is notified. Reference GitHub docs for more details:
          # https://help.github.com/en/articles/about-code-owners
        HEADER
        ignored_teams = T.let(Set.new, T::Set[String])

        github_team_map = CodeTeams.all.each_with_object({}) do |team, map|
          team_github = TeamPlugins::Github.for(team).github
          if team_github.do_not_add_to_codeowners_file
            ignored_teams << team.name
          end

          map[team.name] = team_github.team
        end

        codeowners_file_lines = T.let([], T::Array[String])

        cache.each do |mapper_description, ownership_map_cache|
          ownership_entries = []
          ownership_map_cache.each do |path, code_team|
            team_mapping = github_team_map[code_team.name]
            next if team_mapping.nil?
            next if ignored_teams.include?(code_team.name)
            entry = "/#{path} #{team_mapping}"
            # In order to use the codeowners file as a proper cache, we'll need to insert commented out entries for ignored teams
            # entry = if ignored_teams.include?(code_team.name)
            #   "# /#{path} #{team_mapping}"
            # else
            #   "/#{path} #{team_mapping}"
            # end
            ownership_entries << entry
          end

          next if ownership_entries.none?
          codeowners_file_lines += ['', "# #{mapper_description}", *ownership_entries.sort]
        end

        [
          *header.split("\n"),
          "", # For line between header and codeowners_file_lines
          *codeowners_file_lines,
          "", # For end-of-file newline
        ]
      end

      sig { void }
      def self.write!
        FileUtils.mkdir_p(path.dirname) if !path.dirname.exist?
        path.write(expected_contents_lines.join("\n"))
      end

      sig { returns(Pathname) }
      def self.path
        Pathname.pwd.join('.github/CODEOWNERS')
      end
    end
  end
end