// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package svg

import (
	"bytes"
	"fmt"
	"regexp"
	"sync"
)

type normalizeVarsStruct struct {
	reXMLDoc,
	reComment,
	reAttrXMLNs,
	reAttrSize,
	reAttrClassPrefix *regexp.Regexp
}

var (
	normalizeVars     *normalizeVarsStruct
	normalizeVarsOnce sync.Once
)

// Normalize normalizes the SVG content: set default width/height, remove unnecessary tags/attributes
// It's designed to work with valid SVG content. For invalid SVG content, the returned content is not guaranteed.
func Normalize(data []byte, size int) []byte {
	normalizeVarsOnce.Do(func() {
		normalizeVars = &normalizeVarsStruct{
			reXMLDoc:  regexp.MustCompile(`(?s)<\?xml.*?>`),
			reComment: regexp.MustCompile(`(?s)<!--.*?-->`),

			reAttrXMLNs:       regexp.MustCompile(`(?s)\s+xmlns\s*=\s*"[^"]*"`),
			reAttrSize:        regexp.MustCompile(`(?s)\s+(width|height)\s*=\s*"[^"]+"`),
			reAttrClassPrefix: regexp.MustCompile(`(?s)\s+class\s*=\s*"`),
		}
	})
	data = normalizeVars.reXMLDoc.ReplaceAll(data, nil)
	data = normalizeVars.reComment.ReplaceAll(data, nil)

	data = bytes.TrimSpace(data)
	svgTag, svgRemaining, ok := bytes.Cut(data, []byte(">"))
	if !ok || !bytes.HasPrefix(svgTag, []byte(`<svg`)) {
		return data
	}
	normalized := bytes.Clone(svgTag)
	normalized = normalizeVars.reAttrXMLNs.ReplaceAll(normalized, nil)
	normalized = normalizeVars.reAttrSize.ReplaceAll(normalized, nil)
	normalized = normalizeVars.reAttrClassPrefix.ReplaceAll(normalized, []byte(` class="`))
	normalized = bytes.TrimSpace(normalized)
	normalized = fmt.Appendf(normalized, ` width="%d" height="%d"`, size, size)
	if !bytes.Contains(normalized, []byte(` class="`)) {
		normalized = append(normalized, ` class="svg"`...)
	}
	normalized = append(normalized, '>')
	normalized = append(normalized, svgRemaining...)
	return normalized
}