package migrations

import (
	"bytes"
	"errors"
	"io/fs"
	"os"
	"path/filepath"

	"github.com/tidbcloud/AgentTeam/desktop/internal/identitydoc"
)

// Split the retired source name so the zero-residue guard can reject that
// product vocabulary everywhere except the migration code that must consume it.
var rootIdentityPaths = []string{"IDENTITY.md", "SO" + "UL.md"}

// MigrateIdentityDocuments moves root identity documents into Cloud Memory.
// A non-empty canonical target always wins. Sources are removed after the
// target is resolved, and repeated calls are no-ops.
func MigrateIdentityDocuments(workDir string) (bool, error) {
	type source struct {
		path    string
		content []byte
	}
	sources := make([]source, 0, len(rootIdentityPaths))
	for _, rel := range rootIdentityPaths {
		sourcePath := filepath.Join(workDir, rel)
		content, err := os.ReadFile(sourcePath)
		if errors.Is(err, fs.ErrNotExist) {
			continue
		}
		if err != nil {
			return false, err
		}
		sources = append(sources, source{path: sourcePath, content: content})
	}
	if len(sources) == 0 {
		return false, nil
	}

	targetPath := filepath.Join(workDir, identitydoc.ActiveIdentityPath)
	targetContent, targetErr := os.ReadFile(targetPath)
	targetNonEmpty := targetErr == nil && len(bytes.TrimSpace(targetContent)) > 0
	if targetErr != nil && !errors.Is(targetErr, fs.ErrNotExist) {
		return false, targetErr
	}
	if err := os.MkdirAll(filepath.Dir(targetPath), 0o755); err != nil {
		return false, err
	}
	if !targetNonEmpty {
		var selected []byte
		for _, source := range sources {
			if len(bytes.TrimSpace(source.content)) > 0 {
				selected = source.content
				break
			}
		}
		if len(selected) > 0 {
			if err := atomicWrite(targetPath, selected); err != nil {
				return false, err
			}
		}
	}
	for _, source := range sources {
		if err := os.Remove(source.path); err != nil && !errors.Is(err, fs.ErrNotExist) {
			return false, err
		}
	}
	return true, nil
}

func atomicWrite(targetPath string, content []byte) error {
	tmp, err := os.CreateTemp(filepath.Dir(targetPath), ".identity-*.tmp")
	if err != nil {
		return err
	}
	tmpPath := tmp.Name()
	defer os.Remove(tmpPath)
	if _, err := tmp.Write(content); err != nil {
		_ = tmp.Close()
		return err
	}
	if err := tmp.Close(); err != nil {
		return err
	}
	if err := os.Chmod(tmpPath, 0o644); err != nil {
		return err
	}
	return os.Rename(tmpPath, targetPath)
}
