// Copyright 2023-2024 Gentoo Authors
// Distributed under the terms of the GNU General Public License v2

open System
open System.IO
open System.Threading.Tasks

open SimpleLog.SimpleLog
open System.CommandLine
open System.CommandLine.Invocation

open Gdmt.Shared

let CommandName = "gdmt-gensdk"
let CommandDescription = "maintenance tool to create a .NET SDK distfile"

let SdkVersionArgument = new Argument<string>("sdk-version", ".NET SDK version")

let CompressionTypeOption =
    new Option<string>([| "-C"; "--compression" |], "compression type to use")

CompressionTypeOption.SetDefaultValue "zst"

let TempBaseOption = new Option<string>([| "-t"; "--temp" |], "overwrite temp path")
TempBaseOption.SetDefaultValue(Path.GetTempPath())

let CommandHandler (context: InvocationContext) : Task =
    task {
        let options = context.ParseResult

        let sdkVersion = options.GetValueForArgument SdkVersionArgument
        let compressionType = options.GetValueForOption CompressionTypeOption
        let tempBase = options.GetValueForOption TempBaseOption

        let tempGuid = Guid.NewGuid().ToString()
        let tempName = $"gdmt_gensdk_{tempGuid}"

        let tempPath = Path.Combine(tempBase, tempName)
        let tempSdkPath = Path.Combine(tempPath, $"dotnet-sdk-{sdkVersion}")

        let tempCache = Path.Combine(tempPath, "cache")
        let tempEnvTempdir = Path.Combine(tempCache, "tmpdir")

        let sdkDistTarballName = $"dotnet-sdk-{sdkVersion}.tar.{compressionType}"
        let sdkDistTarballPath = Path.Combine(tempPath, sdkDistTarballName)

        let numThreads = Environment.ProcessorCount
        let numSafeThreads = if numThreads > 2 then numThreads - 2 else 1

        let envMap =
            [ ("TMPDIR", tempEnvTempdir)

              ("DOTNET_ROOT", "")
              ("NUGET_PACKAGES", "")

              ("DOTNET_CLI_TELEMETRY_OPTOUT", "1")
              ("DOTNET_NOLOGO", "1")
              ("DOTNET_SKIP_FIRST_TIME_EXPERIENCE", "1")
              ("MSBUILDDISABLENODEREUSE", "1")

              ("ContinueOnPrebuiltBaselineError", "true")
              ("LogVerbosity", "minimal")
              ("MinimalConsoleLogOutput", "false")
              ("UseSharedCompilation", "false") ]

        for (envKey, envVar) in envMap do
            Environment.SetEnvironmentVariable(envKey, envVar, EnvironmentVariableTarget.Process)

        // Info

        LogMessage Debug $"Temp path:      {tempPath}"
        LogMessage Debug $"Temp SDK path:  {tempSdkPath}"
        LogMessage Debug $"TEMPDIR env:    {tempEnvTempdir}"

        // Clone the official .NET builder project repository.

        Directory.CreateDirectory tempEnvTempdir |> ignore

        LogMessage Debug $"Running repository clone"
        Environment.CurrentDirectory <- tempPath

        let sdkCloneArgs =
            [ "git"
              "clone"
              "--branch"
              $"v{sdkVersion}"
              "--depth"
              "1"
              "--recursive"
              "--shallow-submodules"
              "https://github.com/dotnet/dotnet"
              tempSdkPath ]

        ExecProcess(sdkCloneArgs).Run().Check()
        LogMessage Success $"Repository clone succeeded"

        // Run "prep.sh".

        LogMessage Debug "Running script prep.sh"
        Environment.CurrentDirectory <- tempSdkPath

        ExecProcess([ "git"; "rev-parse"; "HEAD" ]).Run().Check()
        ExecProcess([ "bash"; "prep.sh" ]).Run().Check()
        LogMessage Success $"Script run succeeded"

        // Cleanup.

        LogMessage Debug "Cleaning up"

        ExecProcess([ "rm"; "-f"; "-r"; ".git" ]).Run().Check()

        // Tar up.

        LogMessage Debug $"Creating tarball {sdkDistTarballName}"
        Environment.CurrentDirectory <- tempPath

        Archive.CreateArchive $"dotnet-sdk-{sdkVersion}" sdkDistTarballPath
        LogMessage Success $"Created tarball at path {sdkDistTarballPath}"

        ()
    }

[<EntryPoint>]
let main argv =
    let rootCommand = RootCommand(CommandName)

    rootCommand.Name <- CommandName
    rootCommand.Description <- CommandDescription

    rootCommand.AddArgument SdkVersionArgument

    rootCommand.AddOption CompressionTypeOption
    rootCommand.AddOption TempBaseOption

    rootCommand.SetHandler CommandHandler

    rootCommand.Invoke(argv)
