package secrets

import (
	"context"
	"fmt"
	"log/slog"
	"os"
	"os/exec"
	"strings"

	"gopkg.in/yaml.v3"
)

// SOPSBackend reads secrets from SOPS-encrypted YAML files using the sops CLI.
// This is the DR fallback after Infisical migration.
type SOPSBackend struct {
	secretsDir string
	secrets    map[string]string
	loaded     bool
}

// NewSOPSBackend creates a SOPS backend reading from a directory of .yaml files.
func NewSOPSBackend(secretsDir string) *SOPSBackend {
	return &SOPSBackend{secretsDir: secretsDir}
}

func (s *SOPSBackend) Name() string { return "sops" }

func (s *SOPSBackend) load() error {
	if s.loaded {
		return nil
	}
	s.secrets = make(map[string]string)

	entries, err := os.ReadDir(s.secretsDir)
	if err != nil {
		return fmt.Errorf("read secrets dir: %w", err)
	}

	for _, entry := range entries {
		if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".yaml") {
			continue
		}

		path := s.secretsDir + "/" + entry.Name()
		cmd := exec.Command("sops", "-d", path)
		out, err := cmd.Output()
		if err != nil {
			slog.Warn("sops: decryption failed", "file", entry.Name(), "error", err)
			continue // skip unreadable files
		}

		var data map[string]any
		if err := yaml.Unmarshal(out, &data); err != nil {
			slog.Warn("sops: invalid yaml after decryption", "file", entry.Name(), "error", err)
			continue
		}

		base := strings.TrimSuffix(entry.Name(), ".yaml")
		for k, v := range data {
			s.secrets[base+"/"+k] = fmt.Sprintf("%v", v)
		}
	}

	s.loaded = true
	return nil
}

func (s *SOPSBackend) Get(ctx context.Context, key string) (string, error) {
	if err := s.load(); err != nil {
		return "", err
	}
	val, ok := s.secrets[key]
	if !ok {
		return "", ErrNotFound
	}
	return val, nil
}

func (s *SOPSBackend) List(ctx context.Context) ([]string, error) {
	if err := s.load(); err != nil {
		return nil, err
	}
	keys := make([]string, 0, len(s.secrets))
	for k := range s.secrets {
		keys = append(keys, k)
	}
	return keys, nil
}

func (s *SOPSBackend) Set(ctx context.Context, key string, value string) error {
	return fmt.Errorf("SOPS backend is read-only; use Infisical for writes or sops CLI manually")
}
