package main

import (
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

type InstanceInfo struct {
	ID           string `json:"id"`
	TemplateName string `json:"templateName,omitempty"`
	Port         int    `json:"port"`
	Status       string `json:"status"`
}

func instancesFile(dataDir string) string {
	return filepath.Join(dataDir, "instances.json")
}

func loadInstances(dataDir string) (map[string]*InstanceInfo, error) {
	f := instancesFile(dataDir)
	data, err := os.ReadFile(f)
	if err != nil {
		if os.IsNotExist(err) {
			return make(map[string]*InstanceInfo), nil
		}
		return nil, err
	}
	var list []*InstanceInfo
	if err := json.Unmarshal(data, &list); err != nil {
		return nil, err
	}
	m := make(map[string]*InstanceInfo)
	for _, inst := range list {
		m[inst.ID] = inst
	}
	return m, nil
}

func saveInstances(dataDir string, instances map[string]*InstanceInfo) error {
	if err := os.MkdirAll(dataDir, 0755); err != nil {
		return err
	}
	list := make([]*InstanceInfo, 0, len(instances))
	for _, inst := range instances {
		list = append(list, inst)
	}
	data, err := json.MarshalIndent(list, "", "  ")
	if err != nil {
		return err
	}
	return os.WriteFile(instancesFile(dataDir), data, 0644)
}

func upsertInstance(dataDir string, inst *InstanceInfo) error {
	instances, err := loadInstances(dataDir)
	if err != nil {
		return err
	}
	instances[inst.ID] = inst
	return saveInstances(dataDir, instances)
}

func removeInstance(dataDir, instanceID string) error {
	instances, err := loadInstances(dataDir)
	if err != nil {
		return err
	}
	delete(instances, instanceID)
	return saveInstances(dataDir, instances)
}

func instanceURL(inst *InstanceInfo) string {
	return fmt.Sprintf("http://localhost:%d", inst.Port)
}

func getInstanceStatus(dataDir, instanceID string) string {
	dir := instanceDir(dataDir, instanceID)
	composeFile := filepath.Join(dir, "docker-compose.yml")
	if _, err := os.Stat(composeFile); err != nil {
		return "stopped"
	}

	engine := getContainerEngine()
	cmd := exec.Command(engine, "compose", "-f", composeFile, "ps", "--format", "json")
	out, err := cmd.Output()
	if err != nil {
		return "error"
	}

	outStr := strings.TrimSpace(string(out))
	if outStr == "" || outStr == "[]" {
		return "stopped"
	}

	// Docker compose JSON output can be a single object or an array
	if strings.HasPrefix(outStr, "[") {
		var containers []map[string]interface{}
		if err := json.Unmarshal(out, &containers); err != nil {
			return "error"
		}
		for _, c := range containers {
			state, _ := c["State"].(string)
			if state == "running" {
				return "running"
			}
		}
		return "stopped"
	}

	var c map[string]interface{}
	if err := json.Unmarshal(out, &c); err != nil {
		return "error"
	}
	state, _ := c["State"].(string)
	if state == "running" {
		return "running"
	}
	return "stopped"
}
