package lifecycle

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"

	"github.com/tidbcloud/controlplane9/internal/cluster"
)

// LoadArtifacts reads the persisted lifecycle artifact file.
func LoadArtifacts(stateDir string) (*cluster.ArtifactState, error) {
	data, err := os.ReadFile(cluster.ArtifactsPath(stateDir))
	if err != nil {
		return nil, err
	}

	var artifacts cluster.ArtifactState
	if err := json.Unmarshal(data, &artifacts); err != nil {
		return nil, fmt.Errorf("parse artifact file: %w", err)
	}
	normalizeArtifacts(&artifacts)
	return &artifacts, nil
}

// SaveArtifacts writes the lifecycle artifact file atomically.
func SaveArtifacts(stateDir string, artifacts *cluster.ArtifactState) error {
	if artifacts == nil {
		return fmt.Errorf("artifact state is nil")
	}
	normalizeArtifacts(artifacts)

	if err := os.MkdirAll(stateDir, 0o755); err != nil {
		return fmt.Errorf("create artifact dir: %w", err)
	}

	data, err := json.MarshalIndent(artifacts, "", "  ")
	if err != nil {
		return fmt.Errorf("marshal artifacts: %w", err)
	}

	path := cluster.ArtifactsPath(stateDir)
	tmp, err := os.CreateTemp(filepath.Dir(path), "artifacts.json.*.tmp")
	if err != nil {
		return fmt.Errorf("create artifact temp file: %w", err)
	}
	tmpPath := tmp.Name()
	defer os.Remove(tmpPath)

	if _, err := tmp.Write(data); err != nil {
		_ = tmp.Close()
		return fmt.Errorf("write artifact temp file: %w", err)
	}
	if err := tmp.Close(); err != nil {
		return fmt.Errorf("close artifact temp file: %w", err)
	}
	if err := os.Rename(tmpPath, path); err != nil {
		return fmt.Errorf("rename artifact file: %w", err)
	}
	return nil
}

func normalizeArtifacts(artifacts *cluster.ArtifactState) {
	if artifacts.Services == nil {
		artifacts.Services = make(map[string]*cluster.ServiceArtifact)
	}
	for name, svc := range artifacts.Services {
		if svc == nil {
			artifacts.Services[name] = &cluster.ServiceArtifact{}
			continue
		}
		if svc.Ports == nil {
			svc.Ports = make(map[string]int)
		}
	}
}
