package security

import (
	"html"
	"regexp"
	"strings"

	"github.com/microcosm-cc/bluemonday"
)

// XSSPolicy defines the sanitization policy
type XSSPolicy struct {
	policy *bluemonday.Policy
}

// NewXSSPolicy creates a new XSS sanitization policy
func NewXSSPolicy() *XSSPolicy {
	p := bluemonday.UGCPolicy()

	// Allow basic formatting but strip scripts and dangerous attributes
	p.AllowAttrs("href", "target", "rel").OnElements("a")
	p.AllowAttrs("src", "alt", "width", "height").OnElements("img")
	p.AllowElements("p", "br", "strong", "em", "u", "h1", "h2", "h3", "h4", "h5", "h6")
	p.AllowElements("ul", "ol", "li")

	return &XSSPolicy{policy: p}
}

// SanitizeHTML sanitizes HTML input, allowing safe tags
func (x *XSSPolicy) SanitizeHTML(input string) string {
	return x.policy.Sanitize(input)
}

// SanitizeText completely escapes HTML entities for safe text display
func (x *XSSPolicy) SanitizeText(input string) string {
	return html.EscapeString(input)
}

// SanitizeEmail sanitizes input for use in email contexts
func (x *XSSPolicy) SanitizeEmail(input string) string {
	// For emails, we want to allow basic formatting but be strict
	return strings.TrimSpace(x.SanitizeText(input))
}

// SanitizeURL sanitizes URL input
func (x *XSSPolicy) SanitizeURL(input string) string {
	// Remove javascript: and data: schemes
	dangerous := regexp.MustCompile(`(?i)^(javascript|data|vbscript):`)
	if dangerous.MatchString(input) {
		return ""
	}
	return strings.TrimSpace(input)
}

// SanitizePhoneNumber sanitizes phone number input
func (x *XSSPolicy) SanitizePhoneNumber(input string) string {
	// Remove any HTML tags and trim whitespace
	clean := regexp.MustCompile(`<[^>]*>`).ReplaceAllString(input, "")
	return strings.TrimSpace(clean)
}

// ValidateAndSanitizeInput validates and sanitizes user input
func (x *XSSPolicy) ValidateAndSanitizeInput(input string, fieldType string) (string, error) {
	if strings.TrimSpace(input) == "" {
		return "", nil
	}

	switch fieldType {
	case "text":
		return x.SanitizeText(input), nil
	case "html":
		return x.SanitizeHTML(input), nil
	case "email":
		return x.SanitizeEmail(input), nil
	case "url":
		return x.SanitizeURL(input), nil
	case "phone":
		return x.SanitizePhoneNumber(input), nil
	default:
		return x.SanitizeText(input), nil
	}
}
