package handler

import (
	"net/http"
	"path/filepath"
	"strings"

	"codeberg.org/VARASYS/ZDDC/zddc/internal/config"
	"codeberg.org/VARASYS/ZDDC/zddc/internal/zddc"
)

// ReservedSidecar is the single reserved namespace under any directory. ALL
// server bookkeeping lives under <dir>/.zddc.d/ — bearer tokens
// (.zddc.d/tokens), access logs (.zddc.d/logs), edit history
// (.zddc.d/history), the apps cache (.zddc.d/apps) and the MD-conversion
// cache (.zddc.d/converted).
//
// It is the one hard rule that overrides operator ACLs: a broad grant
// (e.g. `*: rwcd`) must never expose the token store, so .zddc.d is admin-only
// at every depth via this segment-name gate rather than a cascade ACL fence
// (the path-tree cascade has no match-this-name-at-any-depth rule). Everything
// else dot-prefixed is ordinary ACL-governed content; a leading dot only hides
// an entry from directory listings (UI) — see internal/fs and internal/listing.
//
// The gate is applied on reads in dispatch (cmd/zddc-server) and mirrored on
// the write path in authorizeAction. Bearer-token validation reads
// .zddc.d/tokens directly from the filesystem in ACLMiddleware, before any of
// this, so it is never affected by the HTTP-layer gate.
const ReservedSidecar = ".zddc.d"

// HasReservedSidecar reports whether any segment of urlPath is the reserved
// .zddc.d sidecar. The comparison is case-insensitive: ZDDC_ROOT may sit on a
// case-insensitive filesystem (SMB/CIFS/Azure Files), where `.ZDDC.D/tokens`
// resolves to the same directory as `.zddc.d/tokens` — so the gate must catch
// every case variant, not just the literal lowercase form, or a write to a
// case-varied path (e.g. a MOVE destination that skips dispatch's canonical
// case-folding) could reach the token store.
func HasReservedSidecar(urlPath string) bool {
	for _, seg := range strings.Split(strings.Trim(urlPath, "/"), "/") {
		if strings.EqualFold(seg, ReservedSidecar) {
			return true
		}
	}
	return false
}

// ActiveAdminForSidecar reports whether the request's principal is an active
// (elevated) admin with authority over the subtree that contains the first
// .zddc.d segment of urlPath. It is only meaningful when
// HasReservedSidecar(urlPath) is true. Root .zddc.d (e.g. /.zddc.d/tokens)
// requires a root admin; a per-directory .zddc.d (e.g.
// /<proj>/.../.zddc.d/history) requires an admin over that subtree. Bearer
// clients are implicitly elevated by ACLMiddleware, so a CLI caller with admin
// authority passes.
func ActiveAdminForSidecar(cfg config.Config, r *http.Request, urlPath string) bool {
	p := PrincipalFromContext(r)
	if !p.Elevated || p.Email == "" {
		return false
	}
	parent := make([]string, 0)
	for _, seg := range strings.Split(strings.Trim(urlPath, "/"), "/") {
		if strings.EqualFold(seg, ReservedSidecar) {
			break
		}
		parent = append(parent, seg)
	}
	dir := filepath.Join(cfg.Root, filepath.FromSlash(strings.Join(parent, "/")))
	chain, _ := zddc.EffectivePolicy(cfg.Root, dir)
	return zddc.IsAdminForChain(chain, p.Email)
}
