// 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.Restore.Private

let CommandName = "gdmt-restore"
let CommandDescription = "maintenance tool to restore projects"

let ProjectPathOption = new Option<string>([| "-p"; "--project" |], "project path")
ProjectPathOption.SetDefaultValue "."

let SdkVersionOption = new Option<string>([| "-e"; "--sdk-ver" |], "SDK version")
SdkVersionOption.SetDefaultValue "8.0"

let SdkExecutableOption =
    new Option<string>([| "-x"; "--sdk-exe" |], "SDK executable path")

let CacheDirOption =
    new Option<string>([| "-c"; "--cache" |], "cache directory to use")

let ExtraRestoreArgsOption =
    new Option<string>([| "-r"; "--extra-r" |], "extra restore arguments")

let NoFilterOption =
    new Option<bool>([| "-n"; "--no-filter" |], "do not filter NuGets")

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

        let projectPath = options.GetValueForOption(ProjectPathOption) |> Path.GetFullPath

        if not (File.Exists(projectPath) || Directory.Exists(projectPath)) then
            $"project {projectPath} does not exist" |> Exception |> raise

        let cacheDir =
            match options.GetValueForOption(CacheDirOption) with
            | emptyValue when String.IsNullOrEmpty emptyValue -> Path.Combine(projectPath |> GetFileDirectory, ".cache")
            | nonEmptyValue -> nonEmptyValue |> Path.GetFullPath

        let tmpDir = Path.Combine(cacheDir, "tmpdir")
        let nugetPackagesDir = Path.Combine(cacheDir, "nuget_packages")

        let sdkExecutable =
            match options.GetValueForOption(SdkExecutableOption) with
            | emptyValue when String.IsNullOrEmpty emptyValue ->
                SdkVersionOption |> options.GetValueForOption |> FindSdkExecutable
            | nonEmptyValue -> nonEmptyValue

        let extraRestoreArgs = ExtraRestoreArgsOption |> options.GetValueForOption
        let noFilter = NoFilterOption |> options.GetValueForOption

        Directory.CreateDirectory tmpDir |> ignore

        LogMessage Debug $"SDK binary path: {sdkExecutable}"
        LogMessage Debug $"Project path:    {projectPath}"
        LogMessage Debug $"Cache directory: {cacheDir}"
        LogMessage Debug $"TMPDIR:          {tmpDir}"
        LogMessage Debug $"NUGET_PACKAGES:  {nugetPackagesDir}"

        ForEachRuntime(fun runtime ->
            RestoreForRuntime sdkExecutable runtime projectPath tmpDir nugetPackagesDir extraRestoreArgs)

        printfn "Those are the gathered NuGet packages:"
        printfn ""

        GatherNugets (not noFilter) nugetPackagesDir
        |> List.map (fun nuget -> printfn "%s" nuget)
        |> ignore

        ()
    }

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

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

    rootCommand.AddOption ProjectPathOption
    rootCommand.AddOption SdkVersionOption
    rootCommand.AddOption SdkExecutableOption
    rootCommand.AddOption CacheDirOption
    rootCommand.AddOption ExtraRestoreArgsOption
    rootCommand.AddOption NoFilterOption

    rootCommand.SetHandler CommandHandler

    rootCommand.Invoke(argv)
