package plan

import (
	"context"
	"encoding/json"
	"os"
	"sort"
	"strings"

	"metis/pkg/config"
	"metis/pkg/secrets"
)

func fetchSecrets(hostname string) *secrets.NodeSecrets {
	envSecrets := nodeSecretsFromEnv()
	if os.Getenv("VAULT_ADDR") == "" {
		return envSecrets
	}
	cli := secrets.NewFromEnv()
	sec, err := cli.FetchNode(context.Background(), hostname)
	if err != nil {
		return envSecrets
	}
	return mergeNodeSecrets(sec, envSecrets)
}

func nodeSecretsFromEnv() *secrets.NodeSecrets {
	sec := &secrets.NodeSecrets{
		AtlasPassword: strings.TrimSpace(os.Getenv("METIS_NODE_ATLAS_PASSWORD")),
		RootPassword:  strings.TrimSpace(os.Getenv("METIS_NODE_ROOT_PASSWORD")),
	}
	if sec.AtlasPassword == "" && sec.RootPassword == "" {
		return nil
	}
	return sec
}

func mergeNodeSecrets(base, override *secrets.NodeSecrets) *secrets.NodeSecrets {
	if base == nil {
		return override
	}
	if override == nil {
		return base
	}
	merged := *base
	merged.AtlasPassword = firstNonEmptyString(override.AtlasPassword, base.AtlasPassword)
	merged.RootPassword = firstNonEmptyString(override.RootPassword, base.RootPassword)
	merged.K3sToken = firstNonEmptyString(override.K3sToken, base.K3sToken)
	merged.CloudInit = firstNonEmptyString(override.CloudInit, base.CloudInit)
	if len(base.Extra) > 0 || len(override.Extra) > 0 {
		merged.Extra = map[string]string{}
		for key, value := range base.Extra {
			merged.Extra[key] = value
		}
		for key, value := range override.Extra {
			merged.Extra[key] = value
		}
	}
	return &merged
}

func applyNodeMetadataEnv(cfg *config.NodeConfig) {
	if cfg == nil {
		return
	}
	if labels := parseEnvJSONMap(os.Getenv("METIS_NODE_LABELS_JSON")); len(labels) > 0 {
		if cfg.Labels == nil {
			cfg.Labels = map[string]string{}
		}
		for key, value := range labels {
			cfg.Labels[key] = value
		}
		cfg.K3s.Labels = cfg.Labels
	}
	if taints := parseEnvJSONList(os.Getenv("METIS_NODE_TAINTS_JSON")); len(taints) > 0 {
		cfg.Taints = uniqueStrings(append(cfg.Taints, taints...))
		cfg.K3s.Taints = append([]string{}, cfg.Taints...)
	}
}

func parseEnvJSONMap(raw string) map[string]string {
	raw = strings.TrimSpace(raw)
	if raw == "" {
		return nil
	}
	var values map[string]string
	if err := json.Unmarshal([]byte(raw), &values); err != nil {
		return nil
	}
	return values
}

func parseEnvJSONList(raw string) []string {
	raw = strings.TrimSpace(raw)
	if raw == "" {
		return nil
	}
	var values []string
	if err := json.Unmarshal([]byte(raw), &values); err != nil {
		return nil
	}
	return values
}

func uniqueStrings(values []string) []string {
	seen := map[string]struct{}{}
	out := make([]string, 0, len(values))
	for _, value := range values {
		value = strings.TrimSpace(value)
		if value == "" {
			continue
		}
		if _, ok := seen[value]; ok {
			continue
		}
		seen[value] = struct{}{}
		out = append(out, value)
	}
	sort.Strings(out)
	return out
}

func jsonMarshalIndent(value any) ([]byte, error) {
	return json.MarshalIndent(value, "", "  ")
}
