defmodule Refuge.NativeLink.GRPCServer do
  @moduledoc """
  gRPC server implementation for the NativeLink service.
  Handles build requests on port 1985.
  
  Also implements the Bazel Remote Execution API for:
  - ContentAddressableStorage (CAS)
  - ActionCache (AC)
  - Capabilities
  - ByteStream
  """
  # NOTE: We're defining the service in the endpoint instead
  # to avoid conflicts with multiple service implementations
  use GRPC.Server,
    service: Refuge.Nativelink.NativeLinkService.Service

  require Logger

  # Default bazel path and build events configuration
  @bazel_path "/usr/local/bin/bazel"

  @doc """
  Handles gRPC requests to execute a build in the specified directory.
  Corresponds to the ExecuteBuild RPC defined in the protobuf schema.
  """
  @spec execute_build(Refuge.Nativelink.BuildRequest.t(), GRPC.Server.Stream.t()) ::
          Refuge.Nativelink.BuildResponse.t()
  def execute_build(request, _stream) do
    Logger.info("Received build request for directory: #{request.build_dir}")
    
    # Verify that the directory exists
    if !File.dir?(request.build_dir) do
      Logger.error("Build directory does not exist: #{request.build_dir}")
      %Refuge.Nativelink.BuildResponse{
        status: 1,
        build_output: "Error: Build directory does not exist: #{request.build_dir}",
        run_output: nil
      }
    else
      # Get the build target (default to "//..." if not specified)
      target = if request.target && request.target != "", do: request.target, else: "//..."
      Logger.info("Building target: #{target}")
      
      # Run the build command using Bazel
      {build_output, build_status} = 
        System.cmd(
          @bazel_path,
          ["build", target],
          cd: request.build_dir,
          stderr_to_stdout: true
        )
      
      # Run the target if build was successful and it's not a pattern target like //...
      {run_output, _run_status} =
        if build_status == 0 and !String.contains?(target, "...") do
          Logger.info("Running target: #{target}")
          System.cmd(
            @bazel_path,
            ["run", target],
            cd: request.build_dir
          )
        else
          message = if build_status == 0, do: "No run output for pattern target", else: "Failed to run binary"
          Logger.info(message)
          {message, 1}
        end
      
      # Return build results in the response
      %Refuge.Nativelink.BuildResponse{
        status: build_status,
        build_output: build_output,
        run_output: run_output
      }
    end
  end
end
