package renderer

import (
	"fmt"
	"math"
	"strconv"
	"strings"

	"github.com/kevin/go-jdenticon/internal/engine"
)

// SVGPath represents an SVG path element
type SVGPath struct {
	data strings.Builder
}

// AddPolygon adds a polygon to the SVG path
func (p *SVGPath) AddPolygon(points []engine.Point) {
	if len(points) == 0 {
		return
	}

	// Move to first point
	p.data.WriteString(fmt.Sprintf("M%s %s", svgValue(points[0].X), svgValue(points[0].Y)))

	// Line to subsequent points
	for i := 1; i < len(points); i++ {
		p.data.WriteString(fmt.Sprintf("L%s %s", svgValue(points[i].X), svgValue(points[i].Y)))
	}

	// Close path
	p.data.WriteString("Z")
}

// AddCircle adds a circle to the SVG path
func (p *SVGPath) AddCircle(topLeft engine.Point, size float64, counterClockwise bool) {
	sweepFlag := "1"
	if counterClockwise {
		sweepFlag = "0"
	}

	radius := size / 2
	centerX := topLeft.X + radius
	centerY := topLeft.Y + radius
	
	svgRadius := svgValue(radius)
	svgDiameter := svgValue(size)
	svgArc := fmt.Sprintf("a%s,%s 0 1,%s ", svgRadius, svgRadius, sweepFlag)

	// Move to start point (left side of circle)
	startX := centerX - radius
	startY := centerY

	p.data.WriteString(fmt.Sprintf("M%s %s", svgValue(startX), svgValue(startY)))
	p.data.WriteString(svgArc + svgDiameter + ",0")
	p.data.WriteString(svgArc + "-" + svgDiameter + ",0")
}

// DataString returns the SVG path data string
func (p *SVGPath) DataString() string {
	return p.data.String()
}

// SVGRenderer implements the Renderer interface for SVG output
type SVGRenderer struct {
	*BaseRenderer
	pathsByColor map[string]*SVGPath
	colorOrder   []string
}

// NewSVGRenderer creates a new SVG renderer
func NewSVGRenderer(iconSize int) *SVGRenderer {
	return &SVGRenderer{
		BaseRenderer: NewBaseRenderer(iconSize),
		pathsByColor: make(map[string]*SVGPath),
		colorOrder:   make([]string, 0),
	}
}

// SetBackground sets the background color and opacity
func (r *SVGRenderer) SetBackground(fillColor string, opacity float64) {
	r.BaseRenderer.SetBackground(fillColor, opacity)
}

// BeginShape marks the beginning of a new shape with the specified color
func (r *SVGRenderer) BeginShape(color string) {
	r.BaseRenderer.BeginShape(color)
	if _, exists := r.pathsByColor[color]; !exists {
		r.pathsByColor[color] = &SVGPath{}
		r.colorOrder = append(r.colorOrder, color)
	}
}

// EndShape marks the end of the currently drawn shape
func (r *SVGRenderer) EndShape() {
	// No action needed for SVG
}

// getCurrentPath returns the current path for the active color
func (r *SVGRenderer) getCurrentPath() *SVGPath {
	currentColor := r.GetCurrentColor()
	if currentColor == "" {
		return nil
	}
	return r.pathsByColor[currentColor]
}

// AddPolygon adds a polygon with the current fill color to the SVG
func (r *SVGRenderer) AddPolygon(points []engine.Point) {
	if path := r.getCurrentPath(); path != nil {
		path.AddPolygon(points)
	}
}

// AddCircle adds a circle with the current fill color to the SVG
func (r *SVGRenderer) AddCircle(topLeft engine.Point, size float64, invert bool) {
	if path := r.getCurrentPath(); path != nil {
		path.AddCircle(topLeft, size, invert)
	}
}

// ToSVG generates the final SVG XML string
func (r *SVGRenderer) ToSVG() string {
	var svg strings.Builder
	
	iconSize := r.GetSize()
	background, backgroundOp := r.GetBackground()

	// SVG opening tag with namespace and dimensions
	svg.WriteString(fmt.Sprintf(`<svg xmlns="http://www.w3.org/2000/svg" width="%d" height="%d" viewBox="0 0 %d %d">`,
		iconSize, iconSize, iconSize, iconSize))

	// Add background rectangle if specified
	if background != "" && backgroundOp > 0 {
		if backgroundOp >= 1.0 {
			svg.WriteString(fmt.Sprintf(`<rect width="100%%" height="100%%" fill="%s"/>`, background))
		} else {
			svg.WriteString(fmt.Sprintf(`<rect width="100%%" height="100%%" fill="%s" opacity="%.2f"/>`,
				background, backgroundOp))
		}
	}

	// Add paths for each color (in insertion order to preserve z-order)
	for _, color := range r.colorOrder {
		path := r.pathsByColor[color]
		dataString := path.DataString()
		if dataString != "" {
			svg.WriteString(fmt.Sprintf(`<path fill="%s" d="%s"/>`, color, dataString))
		}
	}

	// SVG closing tag
	svg.WriteString("</svg>")

	return svg.String()
}

// svgValue rounds a float64 to one decimal place, mimicking the Jdenticon JS implementation's
// "round half up" behavior. It also formats the number to a minimal string representation.
func svgValue(value float64) string {
	// Use math.Floor to replicate the "round half up" logic from the JS implementation.
	// JavaScript: ((value * 10 + 0.5) | 0) / 10
	rounded := math.Floor(value*10 + 0.5) / 10
	
	// Format to an integer string if there's no fractional part.
	if rounded == math.Trunc(rounded) {
		return strconv.Itoa(int(rounded))
	}
	
	// Otherwise, format to one decimal place.
	return strconv.FormatFloat(rounded, 'f', 1, 64)
}
