package main

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"path/filepath"
	"sync"

	"github.com/nats-io/nats.go"

	"git.zb-server.de/ZB-Server/EscapeFromTeacher/pkg/game"
	"git.zb-server.de/ZB-Server/EscapeFromTeacher/pkg/server"
)

// Globaler Zustand des Servers
var (
	rooms          = make(map[string]*server.Room)
	playerSessions = make(map[string]*server.Room)
	mu             sync.RWMutex
	globalWorld    *game.World
)

func main() {
	log.Println("🚀 Escape From Teacher SERVER startet...")

	// 1. WELT & ASSETS LADEN
	globalWorld = game.NewWorld()
	loadServerAssets(globalWorld)

	// 2. NATS VERBINDUNG
	natsURL := "nats://localhost:4222"
	nc, err := nats.Connect(natsURL)
	if err != nil {
		log.Fatal("❌ Konnte nicht zu NATS verbinden: ", err)
	}
	defer nc.Close()

	ec, err := nats.NewEncodedConn(nc, nats.JSON_ENCODER)
	if err != nil {
		log.Fatal("❌ JSON Encoder Fehler: ", err)
	}
	log.Println("✅ Verbunden mit NATS unter", natsURL)

	// 3. HANDLER: GAME JOIN
	sub, err := ec.Subscribe("game.join", func(req *game.JoinRequest) {
		log.Printf("📥 JOIN empfangen: Name=%s, RoomID=%s", req.Name, req.RoomID)

		playerID := req.Name
		if playerID == "" {
			playerID = "Unknown"
		}

		roomID := req.RoomID
		if roomID == "" {
			roomID = "lobby"
		}

		mu.Lock()
		defer mu.Unlock()

		// Raum finden oder erstellen
		room, exists := rooms[roomID]
		if !exists {
			log.Printf("🆕 Erstelle neuen Raum: '%s'", roomID)
			room = server.NewRoom(roomID, nc, globalWorld)
			rooms[roomID] = room

			// Starte den Game-Loop (Physik)
			go room.RunLoop()
		}

		// Spieler hinzufügen (ID, Name)
		room.AddPlayer(playerID, req.Name)

		// Session speichern
		playerSessions[playerID] = room
		log.Printf("➡️ Spieler '%s' ist Raum '%s' beigetreten.", playerID, roomID)
	})

	if err != nil {
		log.Fatal("❌ Fehler beim Subscribe auf game.join:", err)
	}
	log.Printf("👂 Lausche auf 'game.join'... (Sub Valid: %v)", sub.IsValid())

	// TEST: Auch mit Raw-NATS lauschen
	nc.Subscribe("game.join", func(m *nats.Msg) {
		log.Printf("🔍 RAW NATS: Nachricht empfangen auf game.join: %s", string(m.Data))
	})

	// 4. HANDLER: INPUT
	_, _ = ec.Subscribe("game.input", func(input *game.ClientInput) {
		mu.RLock()
		room, ok := playerSessions[input.PlayerID]
		mu.RUnlock()

		if ok {
			room.HandleInput(*input)
		}
	})

	log.Println("✅ Server bereit. Warte auf Spieler...")

	// Block forever
	select {}
}

func loadServerAssets(w *game.World) {
	assetDir := "./cmd/client/assets"
	chunkDir := filepath.Join(assetDir, "chunks")

	// Manifest laden
	manifestPath := filepath.Join(assetDir, "assets.json")
	data, err := ioutil.ReadFile(manifestPath)
	if err == nil {
		var m game.AssetManifest
		json.Unmarshal(data, &m)
		w.Manifest = m
		log.Printf("📦 Manifest geladen: %d Assets", len(m.Assets))
	} else {
		log.Println("⚠️  Manifest nicht gefunden:", manifestPath)
	}

	// Chunks laden
	files, err := ioutil.ReadDir(chunkDir)
	if err == nil {
		for _, f := range files {
			if filepath.Ext(f.Name()) == ".json" {
				fullPath := filepath.Join(chunkDir, f.Name())
				cData, err := ioutil.ReadFile(fullPath)
				if err == nil {
					var chunk game.Chunk
					json.Unmarshal(cData, &chunk)
					if chunk.ID == "" {
						chunk.ID = f.Name()[0 : len(f.Name())-5]
					}
					w.ChunkLibrary[chunk.ID] = chunk
					log.Printf("🧩 Chunk geladen: %s", chunk.ID)
				}
			}
		}
	} else {
		log.Println("⚠️  Chunk Ordner nicht gefunden:", chunkDir)
	}
}
