# This Source Code Form is subject to the terms of the Mozilla Public License,
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
# obtain one at https://mozilla.org/MPL/2.0/. -}

require 'uri'
require 'net/http'
require 'open3'

LINKER = 'build/rootfs/riscv32-unknown-linux-gnu/bin/ld'
AS = 'build/rootfs/riscv32-unknown-linux-gnu/bin/as'

TMP = Pathname.new('./build')

class BuildTarget
  attr_accessor(:build, :gcc, :sysroot, :tmp)

  def initialize
    @sysroot = Pathname.new '/'
  end

  def gxx
    @gcc.gsub 'c', '+'
  end

  def rootfs
    tmp + 'rootfs'
  end
end

def gcc_verbose(gcc_binary)
  read, write = IO.pipe
  sh({'LANG' => 'C'}, gcc_binary, '--verbose', err: write)
  write.close
  output = read.read
  read.close
  output
end

def find_build_target(gcc_version)
  gcc_binary = 'gcc'
  output = gcc_verbose gcc_binary

  if output.start_with? 'Apple clang'
    gcc_binary = "gcc-#{gcc_version.split('.').first}"
    output = gcc_verbose gcc_binary
    sdk = Pathname.new '/Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk'
  end
  result = output
    .lines
    .each_with_object(BuildTarget.new) do |line, accumulator|
      if line.start_with? 'Target: '
        accumulator.build = line.split(' ').last.strip
      elsif line.start_with? 'COLLECT_GCC'
        accumulator.gcc = line.split('=').last.strip
      end
    end
  result.tmp = TMP
  result.sysroot = sdk unless sdk.nil?
  result
end

def download_and_pipe(url, target, command)
  target.mkpath

  Net::HTTP.start(url.host, url.port, use_ssl: url.scheme == 'https') do |http|
    request = Net::HTTP::Get.new url.request_uri

    http.request request do |response|
      case response
      when Net::HTTPRedirection
        download_and_pipe URI.parse(response['location']), target, command
      when Net::HTTPSuccess
        Dir.chdir target.to_path do
          Open3.popen2(*command) do |stdin, stdout, wait_thread|
            Thread.new do
              stdout.each { |line| puts line }
            end

            response.read_body do |chunk|
              stdin.write chunk
            end
            stdin.close

            wait_thread.value
          end
        end
      else
        response.error!
      end
    end
  end
end