package main

import (
	"flag"
	"log"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"gitea.boner.be/bdnugget/goonscape/game"
	"gitea.boner.be/bdnugget/goonscape/network"
	rl "github.com/gen2brain/raylib-go/raylib"
)

func main() {
	// Set up panic recovery at the top level
	defer func() {
		if r := recover(); r != nil {
			log.Printf("Recovered from fatal panic in main: %v", r)
			// Give the user a chance to see the error
			time.Sleep(5 * time.Second)
		}
	}()

	// Parse command line flags
	verbose := flag.Bool("v", false, "Also show info logs (spammy)")
	local := flag.Bool("local", false, "Connect to local server")
	addr := flag.String("addr", "", "Server address (host or host:port)")
	flag.Parse()

	if *verbose {
		rl.SetTraceLogLevel(rl.LogTrace)
	} else {
		rl.SetTraceLogLevel(rl.LogWarning)
	}

	// Set server address based on flags
	if *local {
		if *addr != "" {
			log.Fatal("Cannot use -local and -addr together")
		}
		network.SetServerAddr("localhost:6969")
	} else if *addr != "" {
		// If port is not specified, append default port
		if !strings.Contains(*addr, ":") {
			*addr += ":6969"
		}
		network.SetServerAddr(*addr)
	}

	// Initialize window with error handling
	rl.SetConfigFlags(rl.FlagMsaa4xHint | rl.FlagWindowResizable) // Enable MSAA and make window resizable
	rl.InitWindow(1024, 768, "GoonScape")

	rl.SetExitKey(0)

	// Initialize audio with error handling
	if !rl.IsAudioDeviceReady() {
		rl.InitAudioDevice()
		if !rl.IsAudioDeviceReady() {
			log.Println("Warning: Failed to initialize audio device, continuing without audio")
		}
	}

	// Use a maximum of 3 attempts to load assets
	var gameInstance *game.Game
	var loadErr error
	maxAttempts := 3

	for attempt := 1; attempt <= maxAttempts; attempt++ {
		gameInstance = game.New()
		loadErr = gameInstance.LoadAssets()
		if loadErr == nil {
			break
		}

		log.Printf("Attempt %d/%d: Failed to load assets: %v", attempt, maxAttempts, loadErr)
		if attempt < maxAttempts {
			log.Println("Retrying...")
			gameInstance.Cleanup() // Cleanup before retrying
			time.Sleep(500 * time.Millisecond)
		}
	}

	if loadErr != nil {
		log.Printf("Failed to load assets after %d attempts. Starting with default assets.", maxAttempts)
	}

	defer func() {
		if gameInstance != nil {
			gameInstance.Cleanup()
		}
		rl.CloseWindow()
		if rl.IsAudioDeviceReady() {
			rl.CloseAudioDevice()
		}
	}()

	rl.SetTargetFPS(60)

	// Play music if available
	if gameInstance.Music.Stream.Buffer != nil {
		rl.PlayMusicStream(gameInstance.Music)
		rl.SetMusicVolume(gameInstance.Music, 0.5)
	}

	// Handle OS signals for clean shutdown
	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
	go func() {
		<-sigChan
		if gameInstance != nil {
			gameInstance.Shutdown()
		}
	}()

	// Keep game loop in main thread for Raylib
	for !rl.WindowShouldClose() {
		deltaTime := rl.GetFrameTime()

		// Update music if available
		if gameInstance.Music.Stream.Buffer != nil {
			rl.UpdateMusicStream(gameInstance.Music)
		}

		func() {
			defer func() {
				if r := recover(); r != nil {
					log.Printf("Recovered from panic in game update: %v", r)
				}
			}()
			gameInstance.Update(deltaTime)
		}()

		func() {
			defer func() {
				if r := recover(); r != nil {
					log.Printf("Recovered from panic in game render: %v", r)
				}
			}()
			gameInstance.Render()
		}()

		// Check if game requested shutdown
		select {
		case <-gameInstance.QuitChan():
			return
		default:
		}
	}
}
