package deploy

import (
	"os"
	"strings"

	"git.solsynth.dev/goatworks/turbine/pkg/launchpad/config"
	"github.com/rs/zerolog/log"
	"gopkg.in/yaml.v3"
)

// --- Docker Compose Structures for YAML Marshalling ---

type ComposeFile struct {
	Version  string                    `yaml:"version"`
	Services map[string]ComposeService `yaml:"services"`
	Networks map[string]interface{}    `yaml:"networks,omitempty"`
}

type ComposeService struct {
	Image       string                       `yaml:"image,omitempty"`
	Build       *ComposeBuild                `yaml:"build,omitempty"`
	Command     interface{}                  `yaml:"command,omitempty"`
	Ports       []string                     `yaml:"ports,omitempty"`
	Expose      []string                     `yaml:"expose,omitempty"`
	Environment map[string]string            `yaml:"environment,omitempty"`
	Volumes     []string                     `yaml:"volumes,omitempty"`
	DependsOn   map[string]config.Dependency `yaml:"depends_on,omitempty"`
	Networks    []string                     `yaml:"networks,omitempty"`
	Healthcheck *config.Healthcheck          `yaml:"healthcheck,omitempty"`
}

type ComposeBuild struct {
	Context    string `yaml:"context,omitempty"`
	Dockerfile string `yaml:"dockerfile,omitempty"`
}

// GenerateDockerCompose creates a docker-compose.yml file from the launchpad config.
func GenerateDockerCompose(cfg config.LaunchpadConfig) {
	compose := ComposeFile{
		Version:  "3.8",
		Services: make(map[string]ComposeService),
		Networks: cfg.Networks,
	}

	for _, s := range cfg.Services {
		subst := func(val string) string {
			return os.ExpandEnv(val)
		}

		composeService := ComposeService{
			Image:     subst(s.Prod.Image),
			Command:   s.Prod.Command,
			Ports:     s.Prod.Ports,
			Expose:    s.Prod.Expose,
			Volumes:   s.Prod.Volumes,
			DependsOn: s.Prod.DependsOn,
			Networks:  s.Prod.Networks,
		}

		// Add healthcheck if defined
		if len(s.Prod.Healthcheck.Test) > 0 {
			composeService.Healthcheck = &s.Prod.Healthcheck
		}

		if s.Prod.Dockerfile != "" {
			context := "."
			if s.Prod.BuildContext != "" {
				context = s.Prod.BuildContext
			}
			composeService.Build = &ComposeBuild{
				Context:    context,
				Dockerfile: s.Prod.Dockerfile,
			}
		}

		if len(s.Prod.Environment) > 0 {
			envMap := make(map[string]string)
			for _, env := range s.Prod.Environment {
				parts := strings.SplitN(subst(env), "=", 2)
				if len(parts) == 2 {
					envMap[parts[0]] = parts[1]
				}
			}
			composeService.Environment = envMap
		}

		compose.Services[s.Name] = composeService
	}

	yamlData, err := yaml.Marshal(&compose)
	if err != nil {
		log.Fatal().Err(err).Msg("Failed to generate YAML for docker-compose")
	}

	outFile := "docker-compose.yml"
	if err := os.WriteFile(outFile, yamlData, 0o644); err != nil {
		log.Fatal().Err(err).Msgf("Failed to write %s", outFile)
	}

	log.Info().Msgf("Successfully generated %s", outFile)
}
