/*
 * BSD 3-Clause License
 * Copyright (c) 2024, NetFireâ„¢ <https://netfire.com/>
 *
 * Redistribution and use in source and binary forms, with or without modification,
 *  are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *  list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors
 *  may be used to endorse or promote products derived from this software without
 *  specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 *  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 *  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package version

import (
	`fmt`
	`strings`

	`golang.org/x/mod/semver`
)

// Detail returns a multiline string containing every possible piece of information we collect.
func (b *BuildInfo) Detail() (ver string) {

	var sb strings.Builder

	sb.WriteString(fmt.Sprintf("%v\n\n", b.short))
	sb.WriteString(fmt.Sprintf("====\nSource Control: %v\nRepo URI: %v\n", b.SourceControl, b.RepoURI))
	if b.TagVersion != "" {
		if b.PostTagCommits > 0 {
			sb.WriteString(fmt.Sprintf("Version Base: %v\nCommit Hash: %v\n", b.TagVersion, b.CommitHash))
		} else {
			sb.WriteString(fmt.Sprintf("Version: %v\n", b.TagVersion))
		}
	} else {
		sb.WriteString(fmt.Sprintf("Version: (Unversioned)\nCommit Hash: %v\n", b.CommitHash))
	}

	// Post-commits
	if b.TagVersion != "" {
		sb.WriteString(fmt.Sprintf("# of Commits Since %v: %v\n", b.TagVersion, b.PostTagCommits))
	} else {
		sb.WriteString(fmt.Sprintf("# of Commits Since %v: %v\n", b.CommitId, b.PostTagCommits))
	}

	sb.WriteString("Uncommitted/Unstaged Changes: ")
	if b.Dirty {
		sb.WriteString("yes (dirty/monkeypatched build)\n")
	} else {
		sb.WriteString("no (clean build)\n")
	}

	if b.TagVersion != "" {
		sb.WriteString(
			fmt.Sprintf(
				"====\nMajor: %v\nMinor: %v\nPatch: %v\n",
				b.Major, b.Minor, b.Patch,
			),
		)
	}
	sb.WriteString("====\n")
	sb.WriteString(b.Meta())

	ver = sb.String()

	return
}

// Short returns a uniquely identifiable version string.
func (b *BuildInfo) Short() (ver string) {

	ver = b.short

	return
}

// Meta returns the build/compile-time info.
func (b *BuildInfo) Meta() (meta string) {

	var sb strings.Builder

	if b.RealBuildUser != b.BuildUser && b.RealBuildUser != "" {
		sb.WriteString(fmt.Sprintf("Real Build User: %v\n", b.RealBuildUser))
		sb.WriteString(fmt.Sprintf("Sudo Build User: %v\n", b.BuildUser))
	} else {
		sb.WriteString(fmt.Sprintf("Build User: %v\n", b.BuildUser))
	}
	sb.WriteString(fmt.Sprintf("Build Time: %v\nBuild Host: %v\nGo Version: %v\n", b.BuildTime, b.BuildHost, b.GoVersion))

	meta = sb.String()

	return
}

// getReMap gets a regex map of map[pattern]match.
func (b *BuildInfo) getReMap() (matches map[string]string) {

	var s string = b.Short()
	var sections []string

	if !semver.IsValid(s) {
		return
	}

	sections = strings.Split(s, ".")

	// The split should contain everything in the third element.
	// Or, if using a "simplified" semver, the last element.
	matches = make(map[string]string)
	for idx, str := range patchRe.FindStringSubmatch(sections[len(sections)-1]) {
		matches[patchRe.SubexpNames()[idx]] = str
	}

	return
}