package dispatcher

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

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

// ensureSessionWorkDirDurable creates a session workdir and establishes a
// crash-durable directory-entry chain back to AgentTeam's configuration directory.
// A later .daemon-state file fsync only protects the file inside workDir; it
// cannot protect a newly-created workDir (or sessions/agent/agents ancestor)
// from disappearing after a host crash unless every containing directory is
// also fsynced.
//
// The complete logical chain is synced even when it already exists. That makes
// a retry repair a prior attempt that successfully called MkdirAll but failed a
// directory fsync before returning. No durable delivery owner or runtime Spawn
// may happen until this function succeeds.
func (d *Dispatcher) ensureSessionWorkDirDurable(workDir string) error {
	syncDir := syncSessionResumeStateDir
	if d != nil && d.sessionWorkDirSync != nil {
		syncDir = d.sessionWorkDirSync
	}
	return ensureDurableDirectoryChain(profile.ConfigDir(), workDir, 0o755, syncDir)
}

func ensureDurableDirectoryChain(root, target string, mode os.FileMode, syncDir func(string) error) error {
	root = strings.TrimSpace(root)
	target = strings.TrimSpace(target)
	if root == "" {
		return fmt.Errorf("durability root is required")
	}
	if target == "" {
		return fmt.Errorf("directory target is required")
	}
	if syncDir == nil {
		return fmt.Errorf("directory sync function is required")
	}

	rootAbs, err := filepath.Abs(root)
	if err != nil {
		return fmt.Errorf("resolve durability root %q: %w", root, err)
	}
	targetAbs, err := filepath.Abs(target)
	if err != nil {
		return fmt.Errorf("resolve directory target %q: %w", target, err)
	}
	rootAbs = filepath.Clean(rootAbs)
	targetAbs = filepath.Clean(targetAbs)
	rel, err := filepath.Rel(rootAbs, targetAbs)
	if err != nil {
		return fmt.Errorf("relate directory target %q to durability root %q: %w", targetAbs, rootAbs, err)
	}
	if rel == ".." || strings.HasPrefix(rel, ".."+string(os.PathSeparator)) || filepath.IsAbs(rel) {
		return fmt.Errorf("directory target %q escapes durability root %q", targetAbs, rootAbs)
	}

	if err := os.MkdirAll(targetAbs, mode); err != nil {
		return fmt.Errorf("create directory chain %q: %w", targetAbs, err)
	}

	// Sync leaf-to-root. Each parent sync durably records the child entry, while
	// syncing the leaf (and every intermediate directory before its parent) makes
	// the newly-created directory inode/content boundary explicit.
	for dir := targetAbs; ; dir = filepath.Dir(dir) {
		if err := syncDir(dir); err != nil {
			return fmt.Errorf("sync directory %q: %w", dir, err)
		}
		if dir == rootAbs {
			break
		}
		parent := filepath.Dir(dir)
		if parent == dir {
			return fmt.Errorf("directory target %q did not reach durability root %q", targetAbs, rootAbs)
		}
	}
	return nil
}
