package main

import (
	"image/color"
	"math"
	"math/rand"

	"github.com/hajimehoshi/ebiten/v2"
	"github.com/hajimehoshi/ebiten/v2/vector"
)

// GroundTile repräsentiert ein Boden-Segment
type GroundTile struct {
	X            float64
	DirtVariants []DirtPatch
	Stones       []Stone
}

// DirtPatch ist ein Dirt-Fleck im Boden
type DirtPatch struct {
	OffsetX float64
	OffsetY float64
	Width   float64
	Height  float64
	Color   color.RGBA
}

// Stone ist ein Stein auf dem Boden
type Stone struct {
	X     float64
	Y     float64
	Size  float64
	Color color.RGBA
	Shape int // 0=rund, 1=eckig
}

// GroundCache speichert generierte Tiles
var groundCache = make(map[int]GroundTile)

// ClearGroundCache leert den Cache (z.B. bei Änderungen)
func ClearGroundCache() {
	groundCache = make(map[int]GroundTile)
}

// GenerateGroundTile generiert ein prozedurales Boden-Segment (gecacht)
func GenerateGroundTile(tileIdx int) GroundTile {
	// Prüfe Cache
	if cached, exists := groundCache[tileIdx]; exists {
		return cached
	}

	// Deterministischer Seed basierend auf Tile-Index
	rng := rand.New(rand.NewSource(int64(tileIdx * 12345)))

	tile := GroundTile{
		X:            float64(tileIdx) * 128.0,
		DirtVariants: make([]DirtPatch, 0),
		Stones:       make([]Stone, 0),
	}

	// Zufällige Dirt-Patches generieren (15-25 pro Tile, kompakt)
	numDirt := 15 + rng.Intn(10)
	maxDirtHeight := 100.0 // Kompakte Erde-Tiefe (100px)
	for i := 0; i < numDirt; i++ {
		darkness := uint8(70 + rng.Intn(40)) // Verschiedene Brauntöne
		tile.DirtVariants = append(tile.DirtVariants, DirtPatch{
			OffsetX: rng.Float64() * 128,
			OffsetY: rng.Float64()*maxDirtHeight + 20, // Nur im sichtbaren Bereich
			Width:   10 + rng.Float64()*30,
			Height:  10 + rng.Float64()*25,
			Color:   color.RGBA{darkness, darkness - 10, darkness - 20, 255},
		})
	}

	// Steine IN der Erde generieren (20-30 pro Tile, nur eckig, kompakt)
	numStones := 20 + rng.Intn(10)
	for i := 0; i < numStones; i++ {
		tile.Stones = append(tile.Stones, Stone{
			X:     rng.Float64() * 128,
			Y:     rng.Float64()*maxDirtHeight + 20, // Nur im sichtbaren Bereich
			Size:  4 + rng.Float64()*8,              // Verschiedene Größen
			Color: color.RGBA{100 + uint8(rng.Intn(50)), 100 + uint8(rng.Intn(50)), 100 + uint8(rng.Intn(50)), 255},
			Shape: 1, // Nur eckig (keine runden Steine mehr)
		})
	}

	// In Cache speichern
	groundCache[tileIdx] = tile
	return tile
}

// RenderGround rendert den Boden mit Bewegung
func (g *Game) RenderGround(screen *ebiten.Image, cameraX float64, viewScale float64) {
	// Tatsächliche Canvas-Größe verwenden
	canvasW, canvasH := screen.Size()

	// Gameplay-Boden-Position (wo Spieler laufen) - mit echter Canvas-Höhe!
	gameFloorY := float32(GetFloorYFromHeight(canvasH))

	// Erde-Tiefe - kompakt (100px) damit Gameplay optimal Platz hat
	maxDirtDepth := float32(100.0)

	// Berechne wie viel Erde sichtbar sein soll (bis zum Bildschirmrand)
	remainingSpace := float32(canvasH) - gameFloorY
	visibleDirtHeight := maxDirtDepth
	if remainingSpace < maxDirtDepth {
		visibleDirtHeight = remainingSpace
	}

	// 1. Basis Gras-Schicht (volle Canvas-Breite, nur dünne Grasnarbe)
	vector.DrawFilledRect(screen, 0, gameFloorY, float32(canvasW), 20, ColGrass, false)

	// 2. Dirt-Schicht (Basis, volle Canvas-Breite, nur sichtbarer Bereich)
	if visibleDirtHeight > 20 {
		vector.DrawFilledRect(screen, 0, gameFloorY+20, float32(canvasW), visibleDirtHeight-20, ColDirt, false)
	}

	// 3. Prozedurale Dirt-Patches und Steine (bewegen sich mit Kamera)
	// Berechne welche Tiles sichtbar sind (basierend auf Canvas-Breite)
	tileWidth := 128.0
	startTile := int(math.Floor(cameraX / tileWidth))
	endTile := int(math.Ceil((cameraX + float64(canvasW)/viewScale) / tileWidth))

	// Tiles rendern
	for tileIdx := startTile; tileIdx <= endTile; tileIdx++ {
		tile := GenerateGroundTile(tileIdx)

		// Dirt-Patches rendern
		for _, dirt := range tile.DirtVariants {
			worldX := tile.X + dirt.OffsetX
			screenX := float32((worldX - cameraX) * viewScale)
			screenY := gameFloorY + float32(dirt.OffsetY)

			// Nur rendern wenn im sichtbaren Bereich (Canvas-Breite verwenden)
			if screenX+float32(dirt.Width) > 0 && screenX < float32(canvasW) {
				vector.DrawFilledRect(screen, screenX, screenY, float32(dirt.Width), float32(dirt.Height), dirt.Color, false)
			}
		}

		// Steine rendern (in der Erde)
		for _, stone := range tile.Stones {
			worldX := tile.X + stone.X
			screenX := float32((worldX - cameraX) * viewScale)
			screenY := gameFloorY + float32(stone.Y)

			// Nur rendern wenn im sichtbaren Bereich (Canvas-Breite verwenden)
			if screenX > -20 && screenX < float32(canvasW)+20 {
				if stone.Shape == 0 {
					// Runder Stein
					vector.DrawFilledCircle(screen, screenX, screenY, float32(stone.Size/2), stone.Color, false)
					// Highlight für 3D-Effekt
					highlightCol := color.RGBA{
						uint8(math.Min(float64(stone.Color.R)+40, 255)),
						uint8(math.Min(float64(stone.Color.G)+40, 255)),
						uint8(math.Min(float64(stone.Color.B)+40, 255)),
						200,
					}
					vector.DrawFilledCircle(screen, screenX-float32(stone.Size*0.15), screenY-float32(stone.Size*0.15), float32(stone.Size/4), highlightCol, false)
				} else {
					// Eckiger Stein
					vector.DrawFilledRect(screen, screenX-float32(stone.Size/2), screenY-float32(stone.Size/2), float32(stone.Size), float32(stone.Size), stone.Color, false)
					// Schatten für 3D-Effekt
					shadowCol := color.RGBA{
						uint8(float64(stone.Color.R) * 0.6),
						uint8(float64(stone.Color.G) * 0.6),
						uint8(float64(stone.Color.B) * 0.6),
						150,
					}
					vector.DrawFilledRect(screen, screenX-float32(stone.Size/2)+2, screenY-float32(stone.Size/2)+2, float32(stone.Size), float32(stone.Size), shadowCol, false)
					// Original drüber
					vector.DrawFilledRect(screen, screenX-float32(stone.Size/2), screenY-float32(stone.Size/2), float32(stone.Size), float32(stone.Size), stone.Color, false)
				}
			}
		}
	}

	// Cache aufräumen (nur Tiles außerhalb des Sichtbereichs entfernen)
	if len(groundCache) > 100 {
		for idx := range groundCache {
			if idx < startTile-10 || idx > endTile+10 {
				delete(groundCache, idx)
			}
		}
	}
}
