#!/usr/bin/env -S dotnet fsi

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

#r "nuget: Fabulous.AST, 0.7.0"
#r "nuget: Org.Xgqt.SimpleLog, 0.0.0"

open System
open System.IO
open System.Net.Http
open System.Text.RegularExpressions

open Fabulous.AST
open Fantomas.Core
open SimpleLog.SimpleLog

open type Fabulous.AST.Ast

let SourceRoot = Path.Combine(__SOURCE_DIRECTORY__, "../../..") |> Path.GetFullPath
let SharedSubproject = Path.Combine(SourceRoot, "gdmt-shared/src/Gdmt.Shared")

let LicenseMappingSourceFile =
    Path.Combine(SharedSubproject, "Ebuild/LicenseMapping.fs")

let RepoUrl = "https://gitweb.gentoo.org/repo/gentoo.git/plain/"
let RepoLicenseMappingFileUrl = $"{RepoUrl}/metadata/license-mapping.conf"
let RepoPath = "/var/db/repos/gentoo"
let RepoLicenseMappingFilePath = $"{RepoPath}/metadata/license-mapping.conf"

let ReadFileFromPath (path: string) : Async<string> =
    async {
        use streamReader = new StreamReader(path)

        return! streamReader.ReadToEndAsync() |> Async.AwaitTask
    }

let ReadFileFromWww (url: string) : Async<string> =
    async {
        use httpClient = new HttpClient()
        let! response = httpClient.GetAsync(url) |> Async.AwaitTask

        return! response.Content.ReadAsStringAsync() |> Async.AwaitTask
    }

let GetLicenseMappingFileContents () : Async<string> =
    async {
        if File.Exists RepoLicenseMappingFilePath then
            LogMessage Debug $"Using file {RepoLicenseMappingFilePath}"

            return! ReadFileFromPath RepoLicenseMappingFilePath
        else
            LogMessage Warning $"Could not use file {RepoLicenseMappingFilePath}"
            LogMessage Debug $"Using URL {RepoLicenseMappingFileUrl}"

            return! ReadFileFromWww RepoLicenseMappingFileUrl
    }

let GetLicenseMappingObject () : (string * string) array =
    let contents = GetLicenseMappingFileContents() |> Async.RunSynchronously

    contents.Split('\n')
    |> Array.filter (fun s -> not (Regex.IsMatch(s, "^#.*$")) && Regex.IsMatch(s, "^.+ = .+$"))
    |> Array.map (fun s ->
        match s.Split('=') with
        | [| spdx; ebuild |] -> (spdx.Trim(), ebuild.Trim())
        | _ -> $"corrupted data, given {s}" |> Exception |> raise)

let SourceAst =
    Namespace("Gdmt.Shared") {
        NestedModule("LicenseMapping") {
            Value(
                "SpdxToEbuildMap",
                AppExpr("Map.ofList") {
                    ListExpr() {
                        for (spdx, ebuild) in GetLicenseMappingObject() do
                            ParenExpr(
                                TupleExpr() {
                                    ConstantExpr($"\"{spdx}\"")
                                    ConstantExpr($"\"{ebuild}\"")
                                }
                            )
                    }
                }
            )
        }
    }

let Oak: NamespaceNode = Tree.compile SourceAst
let Res: string = CodeFormatter.FormatOakAsync(Oak) |> Async.RunSynchronously

LogMessage Debug "Dumping generated source code"
printfn "%s" Res

LogMessage Debug $"Writing source code to file {LicenseMappingSourceFile}"
File.WriteAllText(LicenseMappingSourceFile, Res)
LogMessage Success $"Successfully written to file {LicenseMappingSourceFile}"

LogMessage Success "Code generation completed successfully"
