package zddc

import "path/filepath"

// IsAdmin reports whether email is listed in the admins entry of the ROOT
// .zddc file (<fsRoot>/.zddc). Subdirectory .zddc files' admins keys are
// deliberately ignored by this function — it gates the server-wide debug
// admin role (/.profile/{whoami,config,logs}) which only the bootstrap
// super-admin should reach.
//
// Subtree-scoped admin authority (the "fiefdom" model) is checked via
// IsSubtreeAdmin / CanEditZddc instead.
//
// Patterns use the same glob syntax as acl.allow / acl.deny (see
// MatchesPattern). Returns false if the root file does not exist, has an
// empty Admins list, or no entry matches. An empty email never matches.
func IsAdmin(fsRoot, email string) bool {
	if email == "" {
		return false
	}
	zf, err := ParseFile(filepath.Join(fsRoot, ".zddc"))
	if err != nil {
		return false
	}
	for _, pattern := range zf.Admins {
		if MatchesPattern(pattern, email) {
			return true
		}
	}
	return false
}

// IsSubtreeAdmin reports whether email administers the subtree rooted at
// dirPath. Authority cascades: a match against any Admins entry on the chain
// from fsRoot down to dirPath (inclusive) confers admin rights for dirPath.
//
// This is the read-side check — "can email *see* admin tools for this
// subtree?". For write authority over a specific .zddc file, use
// CanEditZddc, which adds the strict-ancestor rule that prevents
// self-elevation.
func IsSubtreeAdmin(fsRoot, dirPath, email string) bool {
	if email == "" {
		return false
	}
	chain, err := EffectivePolicy(fsRoot, dirPath)
	if err != nil {
		return false
	}
	for _, level := range chain.Levels {
		for _, pattern := range level.Admins {
			if MatchesPattern(pattern, email) {
				return true
			}
		}
	}
	return false
}

// CanEditZddc reports whether email may write or delete <dirPath>/.zddc.
//
// The strict-ancestor rule: authority must come from a .zddc file STRICTLY
// ABOVE dirPath. An admin granted in <dirPath>/.zddc cannot edit that same
// file (which is what grants their own authority) — they can only edit
// .zddc files in deeper subtrees. This prevents a subtree admin from
// adding peers at their own level, removing their delegator, or otherwise
// elevating themselves.
//
// The root file <fsRoot>/.zddc is the bootstrap exception: it has no
// strict ancestor, so it is governed by its own Admins list (the same
// allowlist IsAdmin checks). The very first super-admin is created by
// hand-editing this file at server install time.
func CanEditZddc(fsRoot, dirPath, email string) bool {
	if email == "" {
		return false
	}
	fsRoot = filepath.Clean(fsRoot)
	dirPath = filepath.Clean(dirPath)

	chain, err := EffectivePolicy(fsRoot, dirPath)
	if err != nil || len(chain.Levels) == 0 {
		return false
	}

	// Bootstrap: the root file is governed by its own Admins.
	if dirPath == fsRoot {
		for _, pattern := range chain.Levels[0].Admins {
			if MatchesPattern(pattern, email) {
				return true
			}
		}
		return false
	}

	// Strict-ancestor: scan all levels EXCEPT the deepest, which IS dirPath.
	// EffectivePolicy returns levels ordered root (index 0) → leaf (last).
	for i := 0; i < len(chain.Levels)-1; i++ {
		for _, pattern := range chain.Levels[i].Admins {
			if MatchesPattern(pattern, email) {
				return true
			}
		}
	}
	return false
}
