package provision

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"zlh-agent/internal/state"
)

/*
WriteEula writes eula.txt for all Minecraft variants.
*/
func WriteEula(cfg state.Config) error {
	dir := ServerDir(cfg)
	if err := os.MkdirAll(dir, 0755); err != nil {
		return fmt.Errorf("mkdir for eula: %w", err)
	}

	content := []byte("eula=true\n")
	return os.WriteFile(filepath.Join(dir, "eula.txt"), content, 0644)
}

/*
WriteServerProperties writes server.properties for jar-based Minecraft servers.

Forge/NeoForge generate their own, so they are skipped.
*/
func WriteServerProperties(cfg state.Config) error {
	variant := strings.ToLower(cfg.Variant)

	// Forge/NeoForge auto-generate properties
	if variant == "forge" || variant == "neoforge" {
		return nil
	}

	dir := ServerDir(cfg)
	if err := os.MkdirAll(dir, 0755); err != nil {
		return fmt.Errorf("mkdir for server.properties: %w", err)
	}

	var gamePort int
	if len(cfg.Ports) > 0 {
		gamePort = cfg.Ports[0]
	} else {
		gamePort = 25565
	}

	motd := cfg.World
	if motd == "" {
		motd = "ZeroLagHub Server"
	}

	content := fmt.Sprintf(
		`motd=%s
server-port=%d
query.port=%d
allow-flight=true
online-mode=false
difficulty=normal
max-players=20
`,
		motd, gamePort, gamePort+1,
	)

	return os.WriteFile(filepath.Join(dir, "server.properties"), []byte(content), 0644)
}

/*
WriteStartScript creates start.sh for all supported games.
- Vanilla/Paper/Purpur/Fabric: exec java -jar server.jar
- Forge/NeoForge: use JAVA_TOOL_OPTIONS and run.sh
*/
func WriteStartScript(cfg state.Config) error {
	dir := ServerDir(cfg)
	if err := os.MkdirAll(dir, 0755); err != nil {
		return fmt.Errorf("mkdir for start.sh: %w", err)
	}

	variant := strings.ToLower(cfg.Variant)
	javaBin := filepath.Join(JavaRoot, "java")

	// ------------------------------------------------------------
	// Memory calculation
	// ------------------------------------------------------------
	mem := cfg.MemoryMB
	if mem <= 0 {
		switch variant {
		case "forge", "neoforge":
			mem = 4096 // default Forge memory
		default:
			mem = 2048
		}
	}

	xmx := mem
	xms := mem / 2
	if xms < 512 {
		xms = 512
	}
	if xms > xmx {
		xms = xmx
	}

	// ------------------------------------------------------------
	// Build script based on variant
	// ------------------------------------------------------------
	var script string

	switch variant {

	// ------------------------------------------------------------
	// Forge-based loaders
	// ------------------------------------------------------------
	case "forge", "neoforge":
		script = fmt.Sprintf(
			`#!/bin/bash
cd %s

export JAVA_TOOL_OPTIONS="-Xms%dM -Xmx%dM"

if [ -f "./run.sh" ]; then
    exec /bin/bash ./run.sh
elif [ -f "./run" ]; then
    exec /bin/bash ./run
else
    echo "ERROR: Forge run script not found!"
    exit 1
fi
`, dir, xms, xmx)

	// ------------------------------------------------------------
	// All jar-based servers (vanilla, paper, purpur, fabric, quilt)
	// ------------------------------------------------------------
	default:
		script = fmt.Sprintf(
			`#!/bin/bash
cd %s
exec %s -Xms%dM -Xmx%dM -jar server.jar nogui
`, dir, javaBin, xms, xmx)
	}

	// ------------------------------------------------------------
	// Write start.sh
	// ------------------------------------------------------------
	path := filepath.Join(dir, "start.sh")
	if err := os.WriteFile(path, []byte(script), 0755); err != nil {
		return fmt.Errorf("write start.sh: %w", err)
	}

	return nil
}
