package main

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

	toml "github.com/pelletier/go-toml/v2"
)

// Config is the top-level deployment configuration.
type Config struct {
	Workspace string                 `toml:"workspace"`
	Registry  string                 `toml:"registry"`
	MCDSL     MCDSLConfig            `toml:"mcdsl"`
	Services  []ServiceConfig        `toml:"services"`
	Nodes     map[string]*NodeConfig `toml:"nodes"`
}

// MCDSLConfig points to the shared mcdsl library.
type MCDSLConfig struct {
	Path string `toml:"path"` // relative to workspace
}

// ServiceConfig describes a deployable service.
type ServiceConfig struct {
	Name        string            `toml:"name"`
	Path        string            `toml:"path"`        // relative to workspace
	Images      []string          `toml:"images"`
	Dockerfiles map[string]string `toml:"dockerfiles"` // image name -> Dockerfile path
	UsesMCDSL   bool              `toml:"uses_mcdsl"`
}

// NodeConfig describes a deployment target machine.
type NodeConfig struct {
	Host       string                      `toml:"host"`
	User       string                      `toml:"user"`
	Containers map[string]*ContainerConfig `toml:"containers"`
}

// ContainerConfig describes a container to run on a node.
type ContainerConfig struct {
	Image   string   `toml:"image"`
	Network string   `toml:"network"`
	User    string   `toml:"user"`
	Volumes []string `toml:"volumes"`
	Ports   []string `toml:"ports"`
	Restart string   `toml:"restart"`
	Cmd     []string `toml:"cmd"`
}

// LoadConfig reads and parses a TOML config file.
func LoadConfig(path string) (*Config, error) {
	data, err := os.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("read config %s: %w", path, err)
	}

	var cfg Config
	if err := toml.Unmarshal(data, &cfg); err != nil {
		return nil, fmt.Errorf("parse config %s: %w", path, err)
	}

	return &cfg, nil
}

// FindService looks up a service by name.
func (c *Config) FindService(name string) (*ServiceConfig, error) {
	for i := range c.Services {
		if c.Services[i].Name == name {
			return &c.Services[i], nil
		}
	}
	return nil, fmt.Errorf("service %q not found in config", name)
}

// FindNode looks up a node by name.
func (c *Config) FindNode(name string) (*NodeConfig, error) {
	node, ok := c.Nodes[name]
	if !ok {
		return nil, fmt.Errorf("node %q not found in config", name)
	}
	return node, nil
}

// ServicePath returns the absolute path to a service directory.
func (c *Config) ServicePath(svc *ServiceConfig) string {
	return filepath.Join(c.Workspace, svc.Path)
}

// ImageRef returns the full registry reference for an image
// (e.g. "mcr.svc.mcp.metacircular.net:8443/mc-proxy").
func (c *Config) ImageRef(image string) string {
	return c.Registry + "/" + image
}
