package main

import (
	"bytes"
	_ "embed"
	"log"

	"github.com/hajimehoshi/ebiten/v2/audio"
	"github.com/hajimehoshi/ebiten/v2/audio/mp3"
	"github.com/hajimehoshi/ebiten/v2/audio/wav"
)

const (
	SampleRate = 44100
)

//go:embed web/assets/game.mp3
var gameMusicData []byte

//go:embed web/assets/jump.wav
var jumpSoundData []byte

//go:embed web/assets/pickupCoin.wav
var coinSoundData []byte

//go:embed web/assets/powerUp.wav
var powerUpSoundData []byte

// AudioSystem verwaltet Musik und Sound-Effekte
type AudioSystem struct {
	audioContext *audio.Context

	// Musik
	musicPlayer *audio.Player
	musicVolume float64

	// Sound-Effekte
	jumpSound    []byte
	coinSound    []byte
	powerUpSound []byte
	sfxVolume    float64

	// Mute
	muted bool
}

// NewAudioSystem erstellt ein neues Audio-System
func NewAudioSystem() *AudioSystem {
	log.Println("🎵 Initialisiere Audio-System...")
	ctx := audio.NewContext(SampleRate)

	as := &AudioSystem{
		audioContext: ctx,
		musicVolume:  0.7, // 70% Standard-Lautstärke
		sfxVolume:    0.3, // 30% Standard-Lautstärke
		muted:        false,
	}

	// Musik laden
	log.Printf("📀 Lade Musik (%.2f MB)...", float64(len(gameMusicData))/(1024*1024))
	as.loadMusic()

	// Sound-Effekte dekodieren
	log.Println("🔊 Lade Sound-Effekte...")
	as.jumpSound = as.loadWav(jumpSoundData)
	as.coinSound = as.loadWav(coinSoundData)
	as.powerUpSound = as.loadWav(powerUpSoundData)

	log.Println("✅ Audio-System bereit")
	return as
}

// loadMusic lädt und startet die Hintergrundmusik
func (as *AudioSystem) loadMusic() {
	// MP3 dekodieren
	stream, err := mp3.DecodeWithSampleRate(SampleRate, bytes.NewReader(gameMusicData))
	if err != nil {
		log.Printf("❌ Fehler beim Laden der Musik: %v", err)
		return
	}

	// Infinite Loop
	loop := audio.NewInfiniteLoop(stream, stream.Length())

	// Player erstellen
	player, err := as.audioContext.NewPlayer(loop)
	if err != nil {
		log.Printf("❌ Fehler beim Erstellen des Music Players: %v", err)
		return
	}

	as.musicPlayer = player
	as.updateMusicVolume()

	log.Println("🎵 Musik geladen")
}

// loadWav lädt eine WAV-Datei und gibt die dekodierten Bytes zurück
func (as *AudioSystem) loadWav(data []byte) []byte {
	stream, err := wav.DecodeWithSampleRate(SampleRate, bytes.NewReader(data))
	if err != nil {
		log.Printf("❌ Fehler beim Laden von WAV: %v", err)
		return nil
	}

	// Stream in Bytes lesen
	decoded := bytes.NewBuffer(nil)
	_, err = decoded.ReadFrom(stream)
	if err != nil {
		log.Printf("❌ Fehler beim Dekodieren von WAV: %v", err)
		return nil
	}

	return decoded.Bytes()
}

// PlayMusic startet die Hintergrundmusik
func (as *AudioSystem) PlayMusic() {
	if as.musicPlayer == nil {
		log.Println("⚠️ Music Player ist nil - Musik kann nicht gestartet werden")
		return
	}
	if as.musicPlayer.IsPlaying() {
		log.Println("⚠️ Musik läuft bereits")
		return
	}
	as.musicPlayer.Play()
	log.Printf("▶️ Musik gestartet (Volume: %.2f, Muted: %v)", as.musicVolume, as.muted)
}

// StopMusic stoppt die Hintergrundmusik
func (as *AudioSystem) StopMusic() {
	if as.musicPlayer != nil && as.musicPlayer.IsPlaying() {
		as.musicPlayer.Pause()
		log.Println("⏸️ Musik gestoppt")
	}
}

// PlayJump spielt den Jump-Sound ab
func (as *AudioSystem) PlayJump() {
	if as.muted {
		return
	}
	as.playSoundEffect(as.jumpSound, as.sfxVolume)
}

// PlayCoin spielt den Coin-Pickup-Sound ab
func (as *AudioSystem) PlayCoin() {
	if as.muted {
		return
	}
	as.playSoundEffect(as.coinSound, as.sfxVolume)
}

// PlayPowerUp spielt den PowerUp-Sound ab
func (as *AudioSystem) PlayPowerUp() {
	if as.muted {
		return
	}
	as.playSoundEffect(as.powerUpSound, as.sfxVolume)
}

// playSoundEffect spielt einen Sound-Effekt ab
func (as *AudioSystem) playSoundEffect(soundData []byte, volume float64) {
	if soundData == nil {
		return
	}

	player := as.audioContext.NewPlayerFromBytes(soundData)
	if player == nil {
		return
	}

	player.SetVolume(volume)
	player.Play()
}

// SetMusicVolume setzt die Musik-Lautstärke (0.0 - 1.0)
func (as *AudioSystem) SetMusicVolume(volume float64) {
	as.musicVolume = clamp(volume, 0.0, 1.0)
	as.updateMusicVolume()
}

// SetSFXVolume setzt die Sound-Effekt-Lautstärke (0.0 - 1.0)
func (as *AudioSystem) SetSFXVolume(volume float64) {
	as.sfxVolume = clamp(volume, 0.0, 1.0)
}

// ToggleMute schaltet Mute an/aus
func (as *AudioSystem) ToggleMute() {
	as.muted = !as.muted
	as.updateMusicVolume()
	log.Printf("🔇 Mute: %v", as.muted)
}

// SetMuted setzt Mute-Status
func (as *AudioSystem) SetMuted(muted bool) {
	as.muted = muted
	as.updateMusicVolume()
}

// IsMuted gibt zurück, ob der Sound gemutet ist
func (as *AudioSystem) IsMuted() bool {
	return as.muted
}

// GetMusicVolume gibt die aktuelle Musik-Lautstärke zurück
func (as *AudioSystem) GetMusicVolume() float64 {
	return as.musicVolume
}

// GetSFXVolume gibt die aktuelle SFX-Lautstärke zurück
func (as *AudioSystem) GetSFXVolume() float64 {
	return as.sfxVolume
}

// updateMusicVolume aktualisiert die Musik-Lautstärke
func (as *AudioSystem) updateMusicVolume() {
	if as.musicPlayer != nil {
		if as.muted {
			as.musicPlayer.SetVolume(0)
		} else {
			as.musicPlayer.SetVolume(as.musicVolume)
		}
	}
}

// clamp begrenzt einen Wert zwischen min und max
func clamp(value, min, max float64) float64 {
	if value < min {
		return min
	}
	if value > max {
		return max
	}
	return value
}
