package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"time"
)

// GitHubRelease represents the GitHub API response for a release
type GitHubRelease struct {
	TagName string `json:"tag_name"`
	Name    string `json:"name"`
	HTMLURL string `json:"html_url"`
}

// Version represents a semantic version
type Version struct {
	Major int
	Minor int
	Patch int
}

// parseVersion parses a semantic version string (e.g., "v1.2.3" or "1.2.3")
func parseVersion(versionStr string) (Version, error) {
	// Remove 'v' prefix if present
	versionStr = strings.TrimPrefix(versionStr, "v")

	parts := strings.Split(versionStr, ".")
	if len(parts) != 3 {
		return Version{}, fmt.Errorf("invalid version format: %s", versionStr)
	}

	major, err := strconv.Atoi(parts[0])
	if err != nil {
		return Version{}, fmt.Errorf("invalid major version: %s", parts[0])
	}

	minor, err := strconv.Atoi(parts[1])
	if err != nil {
		return Version{}, fmt.Errorf("invalid minor version: %s", parts[1])
	}

	patch, err := strconv.Atoi(parts[2])
	if err != nil {
		return Version{}, fmt.Errorf("invalid patch version: %s", parts[2])
	}

	return Version{Major: major, Minor: minor, Patch: patch}, nil
}

// isNewer returns true if v2 is newer than v1
func (v1 Version) isNewer(v2 Version) bool {
	if v2.Major > v1.Major {
		return true
	}
	if v2.Major < v1.Major {
		return false
	}

	if v2.Minor > v1.Minor {
		return true
	}
	if v2.Minor < v1.Minor {
		return false
	}

	return v2.Patch > v1.Patch
}

// String returns the version as a string
func (v Version) String() string {
	return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
}

// CheckForUpdate checks GitHub for a newer version and prints an update banner if found
func CheckForUpdate(owner, repo, currentVersion string) error {
	if currentVersion == "version_replaceme" {
		return nil
	}

	// GitHub API URL for latest release
	url := fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/latest", owner, repo)

	// Create HTTP client with timeout
	client := &http.Client{
		Timeout: 10 * time.Second,
	}

	// Make the request
	resp, err := client.Get(url)
	if err != nil {
		return fmt.Errorf("failed to fetch release info: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("GitHub API returned status: %d", resp.StatusCode)
	}

	// Parse the JSON response
	var release GitHubRelease
	if err := json.NewDecoder(resp.Body).Decode(&release); err != nil {
		return fmt.Errorf("failed to parse release info: %w", err)
	}

	// Parse current and latest versions
	currentVer, err := parseVersion(currentVersion)
	if err != nil {
		return fmt.Errorf("invalid current version: %w", err)
	}

	latestVer, err := parseVersion(release.TagName)
	if err != nil {
		return fmt.Errorf("invalid latest version: %w", err)
	}

	// Check if update is available
	if currentVer.isNewer(latestVer) {
		printUpdateBanner(currentVer.String(), latestVer.String(), release.HTMLURL)
	}

	return nil
}

// printUpdateBanner prints a colorful update notification banner
func printUpdateBanner(currentVersion, latestVersion, releaseURL string) {
	const contentWidth = 70 // width between the border lines

	borderTop := "╔" + strings.Repeat("═", contentWidth) + "╗"
	borderMid := "╠" + strings.Repeat("═", contentWidth) + "╣"
	borderBot := "╚" + strings.Repeat("═", contentWidth) + "╝"
	emptyLine := "║" + strings.Repeat(" ", contentWidth) + "║"

	lines := []string{
		borderTop,
		"║" + centerText("UPDATE AVAILABLE", contentWidth) + "║",
		borderMid,
		emptyLine,
		"║  Current Version: " + padRight(currentVersion, contentWidth-19) + "║",
		"║  Latest Version:  " + padRight(latestVersion, contentWidth-19) + "║",
		emptyLine,
		"║  A newer version is available! Please update to get the" + padRight("", contentWidth-56) + "║",
		"║  latest features, bug fixes, and security improvements." + padRight("", contentWidth-56) + "║",
		emptyLine,
		"║  Release URL: " + padRight(releaseURL, contentWidth-15) + "║",
		emptyLine,
		borderBot,
	}

	for _, line := range lines {
		fmt.Println(line)
	}
}

// padRight pads s with spaces on the right to the given width
func padRight(s string, width int) string {
	if len(s) > width {
		return s[:width]
	}
	return s + strings.Repeat(" ", width-len(s))
}

// centerText centers s in a field of width w
func centerText(s string, w int) string {
	if len(s) >= w {
		return s[:w]
	}
	padding := (w - len(s)) / 2
	return strings.Repeat(" ", padding) + s + strings.Repeat(" ", w-len(s)-padding)
}
