package minecraft

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

	"zlh-agent/internal/provcommon"
	"zlh-agent/internal/state"
)

/* --------------------------------------------------------------------------
   Helper: patch any script/arg files that call plain "java "
----------------------------------------------------------------------------*/
func patchForgeJavaCalls(dir string) error {
	entries, err := os.ReadDir(dir)
	if err != nil {
		return err
	}

	for _, e := range entries {
		if e.IsDir() {
			continue
		}

		name := e.Name()
		if !strings.HasSuffix(name, ".sh") &&
			!strings.HasSuffix(name, ".txt") &&
			!strings.HasSuffix(name, ".args") {
			continue
		}

		path := filepath.Join(dir, name)
		data, err := os.ReadFile(path)
		if err != nil {
			continue // best-effort
		}

		content := string(data)
		patched := strings.ReplaceAll(content, "java ", "/opt/zlh/runtime/java ")
		if patched != content {
			fmt.Println("[forge] patching java call in", name)
			if err := os.WriteFile(path, []byte(patched), 0o755); err != nil {
				return fmt.Errorf("write patched %s: %w", name, err)
			}
		}
	}

	return nil
}

/* --------------------------------------------------------------------------
   InstallMinecraftForge
   - Uses cfg.ArtifactPath as the Forge installer path (relative or absolute URL)
   - Installs into /opt/zlh/minecraft/forge/world
----------------------------------------------------------------------------*/
func InstallMinecraftForge(cfg state.Config) error {
	dir := provcommon.ServerDir(cfg)
	if err := os.MkdirAll(dir, 0o755); err != nil {
		return fmt.Errorf("mkdir server dir: %w", err)
	}

	if cfg.ArtifactPath == "" {
		return fmt.Errorf("artifact_path missing for forge install")
	}

	url := provcommon.BuildArtifactURL(cfg.ArtifactPath)

	installerPath := filepath.Join(dir, "forge-installer.jar")

	// Download Forge installer into server dir
	cmdDl := exec.Command("bash", "-c",
		fmt.Sprintf("cd %s && curl -fLo %s %q", dir, "forge-installer.jar", url),
	)
	cmdDl.Stdout = os.Stdout
	cmdDl.Stderr = os.Stderr

	fmt.Println("[forge] downloading installer from:", url)
	if err := cmdDl.Run(); err != nil {
		return fmt.Errorf("forge installer download failed: %w", err)
	}

	javaBin := filepath.Join(provcommon.JavaRoot, "java")

	// Run Forge installer
	cmd := exec.Command("/bin/bash", "-c",
		fmt.Sprintf("cd %s && %s -jar %s --installServer", dir, javaBin, installerPath),
	)

	// Ensure PATH contains our java for any nested calls
	cmd.Env = append(os.Environ(),
		"PATH=/opt/zlh/runtime:/opt/zlh/runtime/java:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
	)

	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	fmt.Println("[forge] running installer in", dir)
	if err := cmd.Run(); err != nil {
		return fmt.Errorf("forge installer failed: %w", err)
	}

	// Patch scripts/args to use /opt/zlh/runtime/java instead of plain "java"
	if err := patchForgeJavaCalls(dir); err != nil {
		return fmt.Errorf("patch java calls: %w", err)
	}

	return nil
}
