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

open System
open System.Threading.Tasks

open System.CommandLine
open System.CommandLine.Invocation

open Gdmt.Shared.Ebuild
open Gdmt.Shared.Git

open Gdmt.Sync.Runners.Eix
open Gdmt.Sync.Runners.Eselect
open Gdmt.Sync.Runners.Git
open Gdmt.Sync.Runners.Pkgcheck
open Gdmt.Sync.Runners.Portage

let CommandName = "gdmt-sync"
let CommandDescription = "synchronize the ebuild repository"

// Remotes

let RemotesArgument = new Argument<string[]>("remotes", "remotes to push to")
RemotesArgument.SetDefaultValue [| "origin" |]

// Git

let GitPullFromRemoteOption =
    Option<string>([| "-f"; "--from" |], "pull from specified remote")

GitPullFromRemoteOption.SetDefaultValue "origin"

let GitSignOrigin =
    Option<bool>([| "-s"; "--sign" |], "sign when pushing to origin remote")

GitSignOrigin.SetDefaultValue false

let GitRunGCOption = Option<bool>([| "-g"; "--gc" |], "collect garbage")
GitRunGCOption.SetDefaultValue false

// System stress

let Nproc = Environment.ProcessorCount

let JobsOption = new Option<int>([| "-j"; "--jobs" |], "max number of jobs")
JobsOption.SetDefaultValue Nproc

let LoadAverageOption =
    new Option<int>([| "-l"; "--load" |], "max number of load average")

LoadAverageOption.SetDefaultValue Nproc

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

        let remotes = options.GetValueForArgument RemotesArgument

        let gitPullFromRemote = options.GetValueForOption GitPullFromRemoteOption
        let gitSignOrigin = options.GetValueForOption GitSignOrigin
        let gitRunGC = options.GetValueForOption GitRunGCOption

        let jobs = options.GetValueForOption JobsOption
        let loadAverage = options.GetValueForOption LoadAverageOption

        CheckEbuildRepository "."
        RemoveIndexLock() // Clean up stale "index.lock".
        RunPkgcheckScan()
        RemoveIndexLock() // Pkgcheck also creates "index.lock".
        RunGitPull gitPullFromRemote

        // First push to origin an d maybe sign.
        if Array.contains "origin" remotes then
            RunGitPush "origin" gitSignOrigin

        // Process other remotes.
        for remote in remotes do
            if remote = "origin" then () else RunGitPush remote false

        RunEgencache jobs loadAverage
        RunEixUpdate()

        if gitRunGC then
            RunGitGC()

        RunGitRefresh()

        RunListNews()
        RunEixShowUpdates()

        ()
    }

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

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

    rootCommand.AddArgument RemotesArgument

    rootCommand.AddOption GitPullFromRemoteOption
    rootCommand.AddOption GitSignOrigin
    rootCommand.AddOption GitRunGCOption

    rootCommand.AddOption JobsOption
    rootCommand.AddOption LoadAverageOption

    rootCommand.SetHandler CommandHandler

    rootCommand.Invoke(argv)
