package engine

import (
	"fmt"
	"strconv"
	"strings"
	"text/template"
)

// GetTemplateFuncs returns all custom template functions
func GetTemplateFuncs() template.FuncMap {
	return template.FuncMap{
		"escapeKotlin":    escapeKotlin,
		"escapeXML":       escapeXML,
		"capitalizeFirst": capitalizeFirst,
		"toLower":         strings.ToLower,
		"toUpper":         strings.ToUpper,
		"replace":         replaceString, // Custom wrapper for piping
		"contains":        strings.Contains,
		"trimPrefix":      strings.TrimPrefix,
		"trimSuffix":      strings.TrimSuffix,
		"trimHash":        trimHash, // Custom wrapper for piping with correct arg order
		"split":           strings.Split,
		"join":            strings.Join,
		"hexToColor":      hexToColor,
		"inc":             inc,
		"dict":            dict,
	}
}

// escapeKotlin escapes special characters for Kotlin strings
func escapeKotlin(s string) string {
	s = strings.ReplaceAll(s, "\\", "\\\\")
	s = strings.ReplaceAll(s, "\"", "\\\"")
	s = strings.ReplaceAll(s, "\n", "\\n")
	s = strings.ReplaceAll(s, "\r", "\\r")
	s = strings.ReplaceAll(s, "\t", "\\t")
	s = strings.ReplaceAll(s, "$", "\\$")
	return s
}

// escapeXML escapes special characters for XML
func escapeXML(s string) string {
	s = strings.ReplaceAll(s, "&", "&amp;")
	s = strings.ReplaceAll(s, "<", "&lt;")
	s = strings.ReplaceAll(s, ">", "&gt;")
	s = strings.ReplaceAll(s, "\"", "&quot;")
	s = strings.ReplaceAll(s, "'", "&apos;")
	return s
}

// capitalizeFirst capitalizes the first letter
func capitalizeFirst(s string) string {
	if s == "" {
		return ""
	}
	return strings.ToUpper(s[:1]) + s[1:]
}

// replaceString replaces old with new in string s (parameter order optimized for piping)
func replaceString(old, new, s string) string {
	return strings.ReplaceAll(s, old, new)
}

// hexToColor converts hex color to Android Color format
// Input: "#3B82F6" or "3B82F6"
// Output: "Color(0xFF3B82F6)"
func hexToColor(hex string) string {
	hex = strings.TrimPrefix(hex, "#")
	if len(hex) != 6 {
		// Invalid hex, return a default color
		return "Color(0xFF6200EE)"
	}
	return fmt.Sprintf("Color(0xFF%s)", strings.ToUpper(hex))
}

// inc increments an integer (useful for indices)
func inc(i int) int {
	return i + 1
}

// dict creates a map for passing multiple values to nested templates
func dict(values ...interface{}) (map[string]interface{}, error) {
	if len(values)%2 != 0 {
		return nil, fmt.Errorf("dict requires even number of arguments")
	}
	dict := make(map[string]interface{}, len(values)/2)
	for i := 0; i < len(values); i += 2 {
		key, ok := values[i].(string)
		if !ok {
			return nil, fmt.Errorf("dict keys must be strings")
		}
		dict[key] = values[i+1]
	}
	return dict, nil
}

// ParseHexColor parses a hex color string and returns RGB values
func ParseHexColor(hex string) (r, g, b int, err error) {
	hex = strings.TrimPrefix(hex, "#")
	if len(hex) != 6 {
		return 0, 0, 0, fmt.Errorf("invalid hex color: %s", hex)
	}

	rgb, err := strconv.ParseUint(hex, 16, 32)
	if err != nil {
		return 0, 0, 0, err
	}

	r = int((rgb >> 16) & 0xFF)
	g = int((rgb >> 8) & 0xFF)
	b = int(rgb & 0xFF)
	return r, g, b, nil
}

// RGBToHex converts RGB values to hex color
func RGBToHex(r, g, b int) string {
	return fmt.Sprintf("%02X%02X%02X", r, g, b)
}

// AdjustBrightness adjusts the brightness of a color
// factor > 1.0 makes it brighter, < 1.0 makes it darker
func AdjustBrightness(hex string, factor float64) string {
	r, g, b, err := ParseHexColor(hex)
	if err != nil {
		return hex
	}

	r = Clamp(int(float64(r)*factor), 0, 255)
	g = Clamp(int(float64(g)*factor), 0, 255)
	b = Clamp(int(float64(b)*factor), 0, 255)

	return RGBToHex(r, g, b)
}

// Clamp restricts a value between min and max (exported for processors)
func Clamp(val, min, max int) int {
	if val < min {
		return min
	}
	if val > max {
		return max
	}
	return val
}

// GetContrastColor returns white or black based on background luminance
func GetContrastColor(bgHex string) string {
	r, g, b, err := ParseHexColor(bgHex)
	if err != nil {
		return "FFFFFF" // Default to white
	}

	// Calculate relative luminance
	luminance := 0.299*float64(r) + 0.587*float64(g) + 0.114*float64(b)

	if luminance > 128 {
		return "000000" // Black for light backgrounds
	}
	return "FFFFFF" // White for dark backgrounds
}

// trimHash removes leading # from hex colors (for use in templates with piping)
func trimHash(s string) string {
	return strings.TrimPrefix(s, "#")
}
