package stacks

import (
	"path/filepath"
	"strings"

	"gitea.dooplex.hu/admin/felhom-controller/internal/appbackup"
)

// Backup classification for the samba stack (R-7 slice 1, [R4]).
//
// samba is CONTROLLER-GENERATED infra: it has no .felhom.yml and its compose binds are absolute
// share paths, so the catalog path (LoadMetadata → ParseComposeClassifiableBinds → ClassifyBinds)
// cannot classify it. Its classification comes from the SHARES REGISTRY instead:
//
//	share.Offsite == true  → ClassMandatory → TierOffsite (offsite) AND TierSecondary (tier-2)
//	share.Offsite == false → ClassOptional  → TierSecondary only (never offsite)
//
// The smb.conf / passdb mounts are deliberately NOT emitted — they are config, not customer data.
//
// EXECUTION (R-7b, v0.145.0 — the gap this note used to describe is CLOSED). Share data now reaches
// BOTH live tiers, but not through this seam: the engines remain structured around a per-app recovery
// unit (backup.RunTier2 still short-circuits on `os.Stat(unitDir)`; the offsite runner still
// enumerates settings.GetOffboxApps()), and Model B′ deliberately left those paths byte-identical.
// Instead the backup package runs a SIBLING shares source off the SAME registry this file reads —
// backup.RunSharesTier2 and backup.runOffboxSharesLeg — applying the identical rule below.
//
// So this function and the shares sources agree by construction on WHAT each share's class is, while
// the sources own WHERE it goes. Keep the rule here in sync with internal/backup/shares_payload.go's
// classifiedShares if it ever changes.
func (m *Manager) sambaClassifiedBinds() ([]appbackup.ClassifiedBind, bool) {
	if m.settings == nil {
		return nil, false
	}
	shares := m.settings.GetSMBShares()
	out := make([]appbackup.ClassifiedBind, 0, len(shares))
	for _, sh := range shares {
		cls := appbackup.ClassOptional
		if sh.Offsite {
			cls = appbackup.ClassMandatory
		}
		out = append(out, appbackup.ClassifiedBind{
			ComposeBind: appbackup.ComposeBind{
				Root:     appbackup.RootHDD,
				RelPath:  m.shareRelPath(sh.Path),
				ReadOnly: sh.ReadOnly,
			},
			Class:  cls,
			Origin: appbackup.OriginExplicit, // the customer's per-share Felhőmentés toggle IS explicit
		})
	}
	return out, true
}

// shareRelPath expresses a share's absolute path relative to its owning registered storage root, so
// the emitted bind matches the (Root, RelPath) + root-path resolution shape the capture-set helpers
// use. A share under no registered root falls back to the path minus its leading slash (never
// absolute — the structural guards reject absolute RelPaths).
func (m *Manager) shareRelPath(path string) string {
	p := filepath.ToSlash(path)
	if m.settings != nil {
		for _, sp := range m.settings.GetStoragePaths() {
			root := filepath.ToSlash(sp.Path)
			if strings.HasPrefix(p, root+"/") {
				return strings.TrimPrefix(p, root+"/")
			}
		}
	}
	return strings.TrimPrefix(p, "/")
}
