// Copyright 2023-2025 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package main

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"

	"golang.org/x/mod/modfile"
)

func main() {
	goModFilepath := filepath.Clean(os.Args[1])
	overridesFilepath := filepath.Clean(os.Args[2])

	if _, err := os.Stat(goModFilepath); err != nil {
		log.Fatalf("File '%s' does not exist\n", goModFilepath)
	}

	if _, err := os.Stat(overridesFilepath); err != nil {
		log.Fatalf("File '%s' does not exist\n", overridesFilepath)
	}

	var (
		bytes     []byte
		overrides map[string]string
		err       error
	)

	if bytes, err = os.ReadFile(overridesFilepath); err != nil {
		log.Fatalf("Unable to read file '%s'\n", overridesFilepath)
	}

	if overrides, err = parseOverrides(string(bytes)); err != nil {
		log.Fatalf("Parse error in file '%s': %s\n", overridesFilepath, err.Error())
	}

	if bytes, err = os.ReadFile(goModFilepath); err != nil {
		log.Fatalf("Unable to read file '%s'\n", goModFilepath)
	}

	file, err := modfile.Parse(goModFilepath, bytes, nil)
	if err != nil {
		log.Fatalf("Unable to parse file '%s'\n", goModFilepath)
	}

	for _, require := range file.Require {
		if !require.Indirect {
			mod := require.Mod.Path
			overrideMod, hasOverride := overrides[mod]
			if hasOverride {
				if overrideMod == "NEVER_UPGRADE_DIRECTLY" {
					// Do not manually update this direct dependency. Treat it like an indirect dep.
					// Let "go mod tidy" update it to be the minimum version required by our other direct deps.
					continue
				}
				mod = overrideMod
			}
			fmt.Printf("go get %s &&\n", mod)
		}
	}

	fmt.Printf("./hack/module.sh tidy\n")
}

func parseOverrides(overridesText string) (map[string]string, error) {
	overridesMap := map[string]string{}

	lines := strings.Split(overridesText, "\n")

	for i, line := range lines {
		trimmedLine := strings.TrimSpace(line)

		if strings.HasPrefix(trimmedLine, "#") || len(trimmedLine) == 0 {
			continue
		}

		splitLine := strings.Split(trimmedLine, " ")

		if len(splitLine) != 2 {
			return nil, fmt.Errorf(
				"error on line %d: found %d tokens instead of 2 tokens",
				i+1, len(splitLine),
			)
		}

		if splitLine[0] == "" || splitLine[1] == "" {
			panic(fmt.Sprintf("unable to parse overrides for line %q", line))
		}

		if splitLine[1] != "NEVER_UPGRADE_DIRECTLY" {
			override := strings.Split(splitLine[1], "@")

			if len(override) != 2 || override[0] == "" || override[1] == "" {
				panic(fmt.Sprintf("unable to parse overrides for line %q ", line))
			}
		}

		overridesMap[splitLine[0]] = splitLine[1]
	}

	return overridesMap, nil
}
