# frozen_string_literal: true

module DiscourseAi
  module AiBot
    module Tools
      class GithubPullRequestDiff < Tool
        LARGE_OBJECT_THRESHOLD = 30_000

        def self.signature
          {
            name: name,
            description: "Retrieves the diff for a GitHub pull request",
            parameters: [
              {
                name: "repo",
                description: "The repository name in the format 'owner/repo'",
                type: "string",
                required: true,
              },
              {
                name: "pull_id",
                description: "The ID of the pull request",
                type: "integer",
                required: true,
              },
            ],
          }
        end

        def self.name
          "github_pull_request_diff"
        end

        def repo
          parameters[:repo]
        end

        def pull_id
          parameters[:pull_id]
        end

        def url
          @url
        end

        def invoke
          api_url = "https://api.github.com/repos/#{repo}/pulls/#{pull_id}"
          @url = "https://github.com/#{repo}/pull/#{pull_id}"

          body = nil
          response_code = "unknown error"

          send_http_request(
            api_url,
            headers: {
              "Accept" => "application/vnd.github.v3.diff",
            },
            authenticate_github: true,
          ) do |response|
            response_code = response.code
            body = read_response_body(response)
          end

          if response_code == "200"
            diff = body
            diff = self.class.sort_and_shorten_diff(diff)
            diff = truncate(diff, max_length: 20_000, percent_length: 0.3, llm: llm)
            { diff: diff }
          else
            { error: "Failed to retrieve the diff. Status code: #{response_code}" }
          end
        end

        def description_args
          { repo: repo, pull_id: pull_id, url: url }
        end

        def self.sort_and_shorten_diff(diff, threshold: LARGE_OBJECT_THRESHOLD)
          # This regex matches the start of a new file in the diff,
          # capturing the file paths for later use.
          file_start_regex = /^diff --git.*/

          prev_start = -1
          prev_match = nil

          split = []

          diff.scan(file_start_regex) do |match|
            match_start = $~.offset(0)[0] # Get the start position of this match

            if prev_start != -1
              full_diff = diff[prev_start...match_start]
              split << [prev_match, full_diff]
            end

            prev_match = match
            prev_start = match_start
          end

          split << [prev_match, diff[prev_start..-1]] if prev_match

          split.sort! { |x, y| x[1].length <=> y[1].length }

          split
            .map do |x, y|
              if y.length < threshold
                y
              else
                "#{x}\nRedacted, Larger than #{threshold} chars"
              end
            end
            .join("\n")
        end
      end
    end
  end
end
