// 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-govendor"
let CommandDescription = "create a Go dependency/vendor archive"

let ProjectDirectoryArgument =
    new Argument<string>("project-directory", "Go project directory to use")

ProjectDirectoryArgument.SetDefaultValue "."

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

CompressionTypeOption.SetDefaultValue "zst"

let OutputPrefixOption =
    new Option<string>([| "-o"; "--output" |], "target archive output path prefix")

let OutputVersionOption =
    new Option<string>([| "-r"; "--outver" |], "version appended to output prefix")

let GoArchiveTypeOption =
    new Option<string>([| "-t"; "--type" |], "Go archive type (dependency/vendor)")

GoArchiveTypeOption.SetDefaultValue "dependency"

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

        let projectDirectory =
            options.GetValueForArgument ProjectDirectoryArgument |> Path.GetFullPath

        let projectName = Path.GetFileName projectDirectory

        let compressionType = options.GetValueForOption CompressionTypeOption
        let outputPrefix = options.GetValueForOption OutputPrefixOption
        let outputVersion = options.GetValueForOption OutputVersionOption

        let goArchiveType = options.GetValueForOption GoArchiveTypeOption

        Environment.CurrentDirectory <- projectDirectory

        let outputPrefixPath =
            let outputPrefixNamed =
                match outputPrefix with
                | p when String.IsNullOrEmpty p -> $"./{projectName}"
                | p -> p

            match outputVersion with
            | v when String.IsNullOrEmpty v -> outputPrefixNamed
            | v -> $"{outputPrefixNamed}-{v}"

        LogMessage Debug $"Project directory:  {projectDirectory}"
        LogMessage Debug $"Project name:       {projectName}"
        LogMessage Debug $"Go archive type:    {goArchiveType}"
        LogMessage Debug $"Output prefix:      {outputPrefixPath}"

        let archivePath =
            match goArchiveType with
            | "dependency" ->
                let archive = $"{outputPrefixPath}-deps.tar.{compressionType}"

                let goModCache = Path.Combine(projectDirectory, "go-mod")
                let goArgs = [ "go"; "mod"; "download"; "-modcacherw"; "-x" ]
                let goEnv = [ ("GOMODCACHE", goModCache) ]

                ExecProcess(goArgs, goEnv).Run().Check()

                Archive.CreateArchive "go-mod" archive

                Path.GetFullPath archive
            | "vendor" ->
                let archive = $"{outputPrefixPath}-vendor.tar.{compressionType}"
                let vendorPath = (Path.Combine(projectName, "vendor"))

                ExecProcess([ "go"; "mod"; "vendor" ]).Run().Check()

                Environment.CurrentDirectory <- ".."
                Archive.CreateArchive vendorPath archive

                Path.GetFullPath archive
            | _ -> $"no known Go archive path, given {goArchiveType}" |> Exception |> raise

        LogMessage Success $"Successfully created archive: {archivePath}"

        ()
    }

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

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

    rootCommand.AddArgument ProjectDirectoryArgument

    rootCommand.AddOption CompressionTypeOption
    rootCommand.AddOption OutputPrefixOption
    rootCommand.AddOption OutputVersionOption
    rootCommand.AddOption GoArchiveTypeOption

    rootCommand.SetHandler CommandHandler

    rootCommand.Invoke(argv)
