package node

import (
	"fmt"

	"iop/packages/go/config"
	iop "iop/proto/gen/iop"
)

// BuildConfigPayload converts a NodeRecord's adapter config to the proto payload
// sent to node during registration.
//
// After config normalisation, OllamaInstances and VllmInstances already contain
// the promoted legacy single-instance entries, so only the slice fields are
// iterated here. Duplicate instance names produce an error.
func BuildConfigPayload(rec *NodeRecord) (*iop.NodeConfigPayload, error) {
	payload := &iop.NodeConfigPayload{
		Runtime: &iop.NodeRuntimeConfig{
			Concurrency:   int32(rec.Runtime.Concurrency),
			WorkspaceRoot: rec.Runtime.WorkspaceRoot,
		},
	}

	payload.Adapters = append(payload.Adapters, &iop.AdapterConfig{
		Type:    "mock",
		Enabled: true,
		Config:  &iop.AdapterConfig_Mock{Mock: &iop.MockAdapterConfig{}},
	})

	seen := make(map[string]struct{})

	for _, inst := range rec.Adapters.OllamaInstances {
		if !inst.Enabled {
			continue
		}
		key := "ollama:" + inst.Name
		if _, dup := seen[key]; dup {
			return nil, fmt.Errorf("duplicate ollama instance name %q", inst.Name)
		}
		seen[key] = struct{}{}
		payload.Adapters = append(payload.Adapters, &iop.AdapterConfig{
			Type:    "ollama",
			Enabled: true,
			Name:    inst.Name,
			Config: &iop.AdapterConfig_Ollama{
				Ollama: &iop.OllamaAdapterConfig{
					BaseUrl:     inst.BaseURL,
					ContextSize: int32(inst.ContextSize),
				},
			},
		})
	}

	for _, inst := range rec.Adapters.VllmInstances {
		if !inst.Enabled {
			continue
		}
		key := "vllm:" + inst.Name
		if _, dup := seen[key]; dup {
			return nil, fmt.Errorf("duplicate vllm instance name %q", inst.Name)
		}
		seen[key] = struct{}{}
		payload.Adapters = append(payload.Adapters, &iop.AdapterConfig{
			Type:    "vllm",
			Enabled: true,
			Name:    inst.Name,
			Config: &iop.AdapterConfig_Vllm{
				Vllm: &iop.VllmAdapterConfig{Endpoint: inst.Endpoint},
			},
		})
	}

	if rec.Adapters.CLI.Enabled {
		profiles := make(map[string]*iop.CLIProfileConfig, len(rec.Adapters.CLI.Profiles))
		for name, p := range rec.Adapters.CLI.Profiles {
			profiles[name] = cliProfileToProto(p)
		}
		payload.Adapters = append(payload.Adapters, &iop.AdapterConfig{
			Type:    "cli",
			Enabled: true,
			Config: &iop.AdapterConfig_Cli{
				Cli: &iop.CLIAdapterConfig{Profiles: profiles},
			},
		})
	}
	return payload, nil
}

func cliProfileToProto(p config.CLIProfileConf) *iop.CLIProfileConfig {
	out := &iop.CLIProfileConfig{
		Command:               p.Command,
		Args:                  append([]string(nil), p.Args...),
		Env:                   append([]string(nil), p.Env...),
		Persistent:            p.Persistent,
		Terminal:              p.Terminal,
		ResponseIdleTimeoutMs: int32(p.ResponseIdleTimeoutMS),
		StartupIdleTimeoutMs:  int32(p.StartupIdleTimeoutMS),
		OutputFormat:          p.OutputFormat,
		Mode:                  p.Mode,
		ResumeArgs:            append([]string(nil), p.ResumeArgs...),
	}
	if !p.CompletionMarker.Empty() {
		out.CompletionMarker = &iop.CLICompletionMarker{
			Line:  p.CompletionMarker.Line,
			Regex: p.CompletionMarker.Regex,
		}
	}
	return out
}
