package parser

import (
	"fmt"
	"strings"
)

type BrazilPath struct {
	Package           string
	FilePath          string
	IsServicePackage  bool
	HasMainlineBranch bool
}

// Packages that do not have a bmg.json file
// Go3p-Github-Pkg-Errors
// Go3p-Github-Golang-Mock
// GoAmzn-Github-Aws-AwsSdkGo

func ParseBrazilPath(fullPath string) *BrazilPath {
	if !strings.Contains(fullPath, "workspace/src") && !strings.Contains(fullPath, "brazil-pkg-cache") {
		return nil
	}

	// Handle paths into Go's std lib
	// E.g. "/opt/brazil-pkg-cache/packages/GoLang/GoLang-1.0.284115.0/RHEL5_64/DEV.STD.PTHREAD/build/lib/src/runtime/asm_amd64.s"
	if strings.Contains(fullPath, "/opt/brazil-pkg-cache/packages/GoLang") {
		// Shorten file path if possible.
		filePath := fullPath
		tokens := strings.Split(fullPath, "/src/")
		if numTokens := len(tokens); numTokens > 1 {
			filePath = tokens[numTokens-1]
		}

		return &BrazilPath{
			Package:  "GoLang",
			FilePath: filePath,
		}
	}

	brazilPath := tryParseDependency(fullPath)
	if brazilPath != nil {
		return brazilPath
	}

	// Handle paths to service code
	// E.g. "/local/p4clients/pkgbuild-XOA_p/workspace/src/StreamSchedule/storage/segments.go"
	tokens := strings.Split(fullPath, "workspace/src/")
	if len(tokens) == 2 {
		// E.g. "StreamSchedule/storage/segments.go"
		pkgAndFile := tokens[1]

		tokens = strings.SplitN(pkgAndFile, "/", 2)
		if len(tokens) != 2 {
			return nil
		}

		return &BrazilPath{
			Package:           tokens[0],
			FilePath:          tokens[1],
			IsServicePackage:  true,
			HasMainlineBranch: true,
		}
	}

	return nil
}

// Try parsing dependency paths, or return nil if the path is not a dependency path.
//
// E.g.
// Path: "/local/p4clients/pkgbuild-xbNT4/workspace/src/TwitchNexus/build/private/bgospace/Go3p-Github-Twitchtv-Twirp/src/github.com/twitchtv/twirp/hooks.go"
// Brazil package: Go3p-Github-Twitchtv-Twirp
// Short path: hooks.go
//
// E.g.
// Path: "/opt/brazil-pkg-cache/packages/StreamSchedule/StreamSchedule-1.0.1215.0/RHEL5_64/generic-flavor/src/build/private/bgospace/Twitch-VXP-Golibs/src/golang.a2z.com/Twitch-VXP-Golibs/middleware/logger.go"
// Brazil package: Twitch-VXP-Golibs
// Short path: middleware/logger.go
func tryParseDependency(fullPath string) *BrazilPath {
	// Paths to dependencies seem to always have a bgospace directory in the path.
	tokens := strings.Split(fullPath, "bgospace/")
	if len(tokens) != 2 {
		return nil
	}

	// pkgAndPath should contain the package name, and a path to the file.
	// E.g "Go3p-Github-Twitchtv-Twirp/src/github.com/twitchtv/twirp/hooks.go"
	// E.g. "Twitch-VXP-Golibs/src/golang.a2z.com/Twitch-VXP-Golibs/middleware/logger.go"
	pkgAndPath := tokens[1]
	tokens = strings.SplitN(pkgAndPath, "/", 2)
	if len(tokens) != 2 {
		return nil
	}

	pkg := tokens[0]
	filePath := tokens[1]

	// This file path is often longer than the file's path in its repository.
	// E.g. We may get a path to "src/golang.a2z.com/Twitch-VXP-Golibs/middleware/logger.go",
	// but in Twitch-VXP-Golibs's repository, the file's path is "middleware/logger.go".
	//
	// Try to shorten the path to match what is in the repository.
	filePath = strings.TrimPrefix(filePath, "src/")

	// Try shortening paths that have the brazil package in there
	// E.g. "code.justin.tv/amzn/StreamScheduleTwirp/twirp.twirp.go" -> "twirp.twirp.go"
	if tokens := strings.Split(filePath, pkg+"/"); len(tokens) > 1 {
		filePath = tokens[len(tokens)-1]

		hasMainlineBranch := true
		if strings.HasSuffix(pkg, "Twirp") {
			hasMainlineBranch = false
		}

		return &BrazilPath{
			Package:           pkg,
			FilePath:          filePath,
			HasMainlineBranch: hasMainlineBranch,
		}
	}

	if strings.HasPrefix(pkg, "Go3p") {
		filePath = shortenGo3pDependencyPath(pkg, filePath)
		return &BrazilPath{
			Package:  pkg,
			FilePath: filePath,
		}
	}

	return &BrazilPath{
		Package:  pkg,
		FilePath: filePath,
	}
}

// E.g. pkg: "Go3p-Github-Twitchtv-Twirp"
//      longPath: "github.com/twitchtv/twirp/hooks.go"
//      return: "hooks.go"
func shortenGo3pDependencyPath(pkg string, longPath string) string {
	// Our strategy to shorten the path is to strip the directories in the path that match the words in the
	// package name.
	// This strategy doesn't work for repos that don't have a bmg.json file.

	// E.g. Go3p-Github-Twitchtv-Twirp -> ["github", "twitchtv", "twirp"]
	pkgTokens := make([]string, 0)
	s := strings.ToLower(pkg)
	s = strings.TrimPrefix(s, "go3p-")
	for _, token := range strings.Split(s, "-") {
		pkgTokens = append(pkgTokens, strings.ToLower(token))
	}

	// Verify that the path has Strip the directories in the path that match
	pathTokens := strings.Split(longPath, "/")
	if len(pathTokens) <= len(pkgTokens) {
		return longPath
	}
	for i, pkgToken := range pkgTokens {
		pathToken := pathTokens[i]
		if !strings.Contains(pathToken, pkgToken) {
			return longPath
		}
	}

	pathTokens = pathTokens[len(pkgTokens):]
	shortPath := strings.Join(pathTokens, "/")
	return shortPath
}

func createFileURL(pkg, filePath string, line int32) string {
	return fmt.Sprintf("https://code.amazon.com/packages/%s/blobs/mainline/--/%s#L%d", pkg, filePath, line)
}

func createPackageURL(pkg string) string {
	return fmt.Sprintf("https://code.amazon.com/packages/%s", pkg)
}
