package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"time"

	"gopkg.in/yaml.v3"
)

const fmConfig = "config.yml"

type GoConfig struct {
	Config struct {
		ServDir    string `yaml:"serverFolder"`
		ServPort   int    `yaml:"port"`
		WorldFile  string `yaml:"worldFile"`
		ServCfg    string `yaml:"serverSettings"`
		ServExec   string `yaml:"serverExec"`
		BackupDir  string `yaml:"backupDir"`
		UseScreen  bool   `yaml:"screen"`
		ScreenName string `yaml:"screenName"`
	} `yaml:"server"`
}

func readCfg(factCfg string) GoConfig {
	//read config file (YAML)
	fileBytes, err := os.ReadFile(factCfg)
	if err != nil {
		log.Fatalf("Error reading config file: %v", err)
	}
	// return Struct
	var config GoConfig
	err = yaml.Unmarshal(fileBytes, &config)
	if err != nil {
		log.Fatalf("Error unmarshalling YAML file: %v", err)
	}
	return config
}

func startStopServer(cmd string, con GoConfig) {
	switch cmd {
	case "start":
		x := fmt.Sprintf("%s --port %d --server-settings %s --start-server %s", con.Config.ServExec, con.Config.ServPort, con.Config.ServCfg, con.Config.WorldFile)

		//x := fmt.Sprintf("%s --port %d --server-settings %s --start-server %s; exec sh", con.Config.ServExec, con.Config.ServPort, con.Config.ServCfg, con.Config.WorldFile)
		///home/raum/factorio-serverfmt.Println(x)
		if con.Config.UseScreen {
			fmt.Println("Starting factorio server in screen session")
			startScreenCmd := exec.Command("screen", "-dmS", con.Config.ScreenName, "bash", "-c", x, "; exec sh")
			err := startScreenCmd.Run()
			if err != nil {
				log.Fatalf("Failed to start server: %s", err)
			} else {
				fmt.Printf("Started server on port %d, in screen named %s\n", con.Config.ServPort, con.Config.ScreenName)
			}
		} else {
			startSrvCmd := exec.Command(x)
			err := startSrvCmd.Run()
			if err != nil {
				log.Fatalf("Failed to start server: %s", err)
			}
		}
	case "stop":
		quitServerCmd := exec.Command("screen", "-S", con.Config.ScreenName, "-p", "0", "-X", "stuff", "/quit\n")
		err := quitServerCmd.Run()
		if err != nil {
			log.Fatalf("Command failed: %s, Error: %v", quitServerCmd.Args, err)
		} else {
			fmt.Printf("Server in screen %s stopped\n", con.Config.ScreenName)
		}
		fmt.Println("Waiting for server to shutdown\r")
		//time.Sleep(20 * time.Second)
		//fmt.Println("Closing screen session ", con.Config.ScreenName)
		//stopScreenCmd := exec.Command("screen", "-S", con.Config.ScreenName, "-p", "0", "-X", "stuff", "exit\n")
		//err = stopScreenCmd.Run()
		//if err != nil {
		//	log.Fatalf("Command failed: %s, Error: %v", stopScreenCmd.Args, err)
		//} else {
		//	fmt.Printf("Screen \"%s\" closed\n", con.Config.ScreenName)
		//}
	}
}

func backUp(cmd string, c GoConfig) {
	switch cmd {
	case "full":
		fmt.Println("Starting full server backup")
		t := time.Now()
		timeStamp := t.Format(time.RFC3339)
		fullBackupName := fmt.Sprintf("%s/ServerBackup.%s.tgz", c.Config.BackupDir, timeStamp)
		fullBackup := exec.Command("tar", "-czf", fullBackupName, c.Config.ServDir)
		err := fullBackup.Run()
		if err != nil {
			fmt.Printf("Backup Failed: %s\n", err)
		}
	case "saves":
		fmt.Println("Backing up saves")
		t := time.Now()
		timeStamp := t.Format(time.RFC3339)
		savesBackupName := fmt.Sprintf("%s/SaveBackup.%s.tgz", c.Config.BackupDir, timeStamp)
		saveDir := fmt.Sprintf("%s/saves", c.Config.ServDir)
		savesBackup := exec.Command("tar", "-czf", savesBackupName, saveDir)
		err := savesBackup.Run()
		if err != nil {
			fmt.Printf("Backup Failed: %s\n", err)
		}
	}
}

func main() {
	c := readCfg(fmConfig)

	if len(os.Args) > 1 {
		switch os.Args[1] {
		case "start":
			startStopServer("start", c)
		case "stop":
			startStopServer("stop", c)
		case "backup":
			if len(os.Args) > 2 {
				switch os.Args[2] {
				case "full":
					backUp("full", c)
				case "saves":
					backUp("saves", c)
				default:
					fmt.Println("Invalid backup type: use 'full' or 'saves'")
				}
			} else {
				fmt.Println("Missing backup type: use 'full' or 'saves'")
			}
		default:
			fmt.Printf("Unknown command: %s. Use 'start', 'stop', or 'backup'.\n", os.Args[1])
		}
	} else {
		fmt.Println("Use 'start', 'stop', or 'backup' command")
		fmt.Println("ex. factoryman start")
		fmt.Println("To configure edit 'conifg.yml'")
	}
}
