package crd

import (
	"bufio"
	"context"
	"fmt"
	"log"
	"maps"
	"os"
	"strings"

	"gopkg.in/yaml.v3"

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

// ProcessSecrets reads secret sources from config and applies them to the local cluster.
func ProcessSecrets(ctx context.Context, applier *Applier, secrets map[string]config.SecretSource, namespace string) []SecretResult {
	var results []SecretResult

	for svc, src := range secrets {
		result := processServiceSecret(ctx, applier, svc, src, namespace)
		results = append(results, result)
	}

	return results
}

func processServiceSecret(ctx context.Context, applier *Applier, service string, src config.SecretSource, namespace string) SecretResult {
	data := make(map[string]string)

	// Load from env file if specified.
	if src.EnvFile != "" {
		envData, err := ParseEnvFile(src.EnvFile)
		if err != nil {
			return SecretResult{Service: service, Status: "failed",
				Error: fmt.Sprintf("read env file %s: %v", src.EnvFile, err)}
		}
		maps.Copy(data, envData)
	}

	// Merge inline values (override env file).
	maps.Copy(data, src.Values)

	if len(data) == 0 {
		return SecretResult{Service: service, Status: "ok", KeyCount: 0}
	}

	secretYAML, err := GenerateSecretYAML(service, namespace, data)
	if err != nil {
		return SecretResult{Service: service, Status: "failed",
			Error: fmt.Sprintf("generate secret: %v", err)}
	}

	log.Printf("crd: applying secret for %s (%d keys)", service, len(data))
	if err := applier.Apply(ctx, secretYAML); err != nil {
		return SecretResult{Service: service, Status: "failed",
			Error: fmt.Sprintf("apply secret: %v", err)}
	}

	return SecretResult{Service: service, Status: "ok", KeyCount: len(data)}
}

// ParseEnvFile reads a .env file and returns key=value pairs.
// Handles blank lines, # comments, KEY=VALUE, KEY="VALUE", KEY='VALUE', and export KEY=VALUE.
func ParseEnvFile(path string) (map[string]string, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	result := make(map[string]string)
	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())

		// Skip blank lines and comments.
		if line == "" || strings.HasPrefix(line, "#") {
			continue
		}

		// Strip optional "export " prefix.
		line = strings.TrimPrefix(line, "export ")

		key, value, ok := strings.Cut(line, "=")
		if !ok {
			continue
		}

		key = strings.TrimSpace(key)
		value = strings.TrimSpace(value)

		// Unquote double or single quotes.
		if len(value) >= 2 {
			if (value[0] == '"' && value[len(value)-1] == '"') ||
				(value[0] == '\'' && value[len(value)-1] == '\'') {
				value = value[1 : len(value)-1]
			}
		}

		result[key] = value
	}

	return result, scanner.Err()
}

// secretManifest is the structure for a Kubernetes Secret YAML.
type secretManifest struct {
	APIVersion string            `yaml:"apiVersion"`
	Kind       string            `yaml:"kind"`
	Metadata   secretMetadata    `yaml:"metadata"`
	Type       string            `yaml:"type"`
	StringData map[string]string `yaml:"stringData"`
}

type secretMetadata struct {
	Name      string `yaml:"name"`
	Namespace string `yaml:"namespace"`
}

// GenerateSecretYAML creates a Kubernetes Secret manifest from key-value pairs.
func GenerateSecretYAML(name, namespace string, data map[string]string) ([]byte, error) {
	if namespace == "" {
		namespace = "default"
	}

	manifest := secretManifest{
		APIVersion: "v1",
		Kind:       "Secret",
		Metadata: secretMetadata{
			Name:      name,
			Namespace: namespace,
		},
		Type:       "Opaque",
		StringData: data,
	}

	return yaml.Marshal(manifest)
}
