// Copyright 2025 Emiliano Spinella (eminwux)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

package controller

import (
	"errors"
	"fmt"
	"os"
	"strconv"

	"github.com/eminwux/kukeon/internal/apischeme"
	"github.com/eminwux/kukeon/internal/consts"
	"github.com/eminwux/kukeon/internal/errdefs"
	intmodel "github.com/eminwux/kukeon/internal/modelhub"
	"github.com/eminwux/kukeon/internal/util/naming"
	v1beta1 "github.com/eminwux/kukeon/pkg/api/model/v1beta1"
)

// RealmSection holds the bootstrap outcome for a single realm.
type RealmSection struct {
	RealmName                          string
	RealmContainerdNamespace           string
	RealmMetadataExistsPre             bool
	RealmMetadataExistsPost            bool
	RealmContainerdNamespaceExistsPre  bool
	RealmContainerdNamespaceExistsPost bool
	RealmContainerdNamespaceCreated    bool
	RealmCreated                       bool
	RealmCgroupExistsPre               bool
	RealmCgroupExistsPost              bool
	RealmCgroupCreated                 bool
}

// SpaceSection holds the bootstrap outcome for a single space.
type SpaceSection struct {
	SpaceName                 string
	SpaceCNINetworkName       string
	SpaceMetadataExistsPre    bool
	SpaceMetadataExistsPost   bool
	SpaceCNINetworkExistsPre  bool
	SpaceCNINetworkExistsPost bool
	SpaceCNINetworkCreated    bool
	SpaceCreated              bool
	SpaceCgroupExistsPre      bool
	SpaceCgroupExistsPost     bool
	SpaceCgroupCreated        bool
}

// StackSection holds the bootstrap outcome for a single stack.
type StackSection struct {
	StackName               string
	StackMetadataExistsPre  bool
	StackMetadataExistsPost bool
	StackCreated            bool
	StackCgroupExistsPre    bool
	StackCgroupExistsPost   bool
	StackCgroupCreated      bool
}

// CellSection holds the bootstrap outcome for a single cell.
type CellSection struct {
	CellName                    string
	CellMetadataExistsPre       bool
	CellMetadataExistsPost      bool
	CellCreated                 bool
	CellCgroupExistsPre         bool
	CellCgroupExistsPost        bool
	CellCgroupCreated           bool
	CellRootContainerExistsPre  bool
	CellRootContainerExistsPost bool
	CellRootContainerCreated    bool
	CellStartedPre              bool
	CellStartedPost             bool
	CellStarted                 bool
	// CellRecreatedDueToImageDrift is true when bootstrapCell observed a
	// persisted cell whose root container image diverged from the desired
	// image and dropped into a stop+delete+recreate branch instead of the
	// idempotent EnsureCell+StartCell path. Issue #868: without this branch,
	// `kuke init --kukeond-image <new>` would silently keep starting the
	// stale container record left behind by a prior reset, and the running
	// daemon binary would never refresh across a `make dev-init` re-bootstrap.
	CellRecreatedDueToImageDrift bool
	// CellPriorImage carries the persisted root container image observed at
	// drift detection time, so the init report can render
	// "recreated (image drift: <old> → <new>)" instead of the misleading
	// "already existed" line on the recreate branch.
	CellPriorImage string
}

type BootstrapReport struct {
	RunPath string

	KukeonCgroupExistsPre  bool
	KukeonCgroupExistsPost bool
	KukeonCgroupCreated    bool

	// CNI bootstrap details
	CniConfigDir           string
	CniCacheDir            string
	CniBinDir              string
	CniConfigDirExistsPre  bool
	CniCacheDirExistsPre   bool
	CniBinDirExistsPre     bool
	CniConfigDirCreated    bool
	CniCacheDirCreated     bool
	CniBinDirCreated       bool
	CniConfigDirExistsPost bool
	CniCacheDirExistsPost  bool
	CniBinDirExistsPost    bool

	// Default user hierarchy (realm=default, space=default, stack=default, no cell).
	DefaultRealm RealmSection
	DefaultSpace SpaceSection
	DefaultStack StackSection

	// System hierarchy (realm=kuke-system, space=kukeon, stack=kukeon, cell=kukeond).
	SystemRealm RealmSection
	SystemSpace SpaceSection
	SystemStack StackSection
	SystemCell  CellSection

	// KukeondImage is the resolved image reference provisioned for the kukeond
	// container inside the system cell.
	KukeondImage string
}

func (b *Exec) bootstrapKukeonCgroup(report BootstrapReport) (BootstrapReport, error) {
	existsPre, created, err := b.runner.EnsureKukeonRootCgroup()
	if err != nil {
		return report, err
	}
	report.KukeonCgroupExistsPre = existsPre
	report.KukeonCgroupExistsPost = true
	report.KukeonCgroupCreated = created
	return report, nil
}

func (b *Exec) bootstrapRealm(section *RealmSection, realmName, realmNamespace string) error {
	section.RealmName = realmName
	section.RealmContainerdNamespace = realmNamespace

	lookupRealm := intmodel.Realm{
		Metadata: intmodel.RealmMetadata{
			Name: realmName,
		},
	}

	internalRealmPre, err := b.runner.GetRealm(lookupRealm)
	if err != nil {
		if errors.Is(err, errdefs.ErrRealmNotFound) {
			section.RealmMetadataExistsPre = false
		} else {
			return fmt.Errorf("%w: %w", errdefs.ErrGetRealm, err)
		}
	} else {
		section.RealmMetadataExistsPre = true
		cgroupExists, cgroupErr := b.runner.ExistsCgroup(internalRealmPre)
		if cgroupErr != nil {
			return fmt.Errorf("failed to check if realm cgroup exists: %w", cgroupErr)
		}
		section.RealmCgroupExistsPre = cgroupExists
	}
	nsExistsPre, err := b.runner.ExistsRealmContainerdNamespace(realmNamespace)
	if err != nil {
		return fmt.Errorf("%w: %w", errdefs.ErrCheckNamespaceExists, err)
	}
	section.RealmContainerdNamespaceExistsPre = nsExistsPre

	realmDoc := &v1beta1.RealmDoc{
		Metadata: v1beta1.RealmMetadata{
			Name: realmName,
			Labels: map[string]string{
				consts.KukeonRealmLabelKey: realmNamespace,
			},
		},
		Spec: v1beta1.RealmSpec{
			Namespace: realmNamespace,
		},
	}

	realm, _, err := apischeme.NormalizeRealm(*realmDoc)
	if err != nil {
		return fmt.Errorf("%w: %w", errdefs.ErrConversionFailed, err)
	}

	if section.RealmMetadataExistsPre {
		if _, err = b.runner.EnsureRealm(internalRealmPre); err != nil {
			return fmt.Errorf("%w: %w", errdefs.ErrCreateRealm, err)
		}
	} else {
		if _, err = b.runner.CreateRealm(realm); err != nil && !errors.Is(err, errdefs.ErrNamespaceAlreadyExists) {
			return fmt.Errorf("%w: %w", errdefs.ErrCreateRealm, err)
		}
	}

	internalRealmPost, err := b.runner.GetRealm(lookupRealm)
	if err != nil {
		if errors.Is(err, errdefs.ErrRealmNotFound) {
			section.RealmMetadataExistsPost = false
		} else {
			return fmt.Errorf("%w: %w", errdefs.ErrGetRealm, err)
		}
	} else {
		section.RealmMetadataExistsPost = true
		cgroupExists, cgroupErr := b.runner.ExistsCgroup(internalRealmPost)
		if cgroupErr != nil {
			return fmt.Errorf("failed to check if realm cgroup exists: %w", cgroupErr)
		}
		section.RealmCgroupExistsPost = cgroupExists
	}
	nsExistsPost, err := b.runner.ExistsRealmContainerdNamespace(realmNamespace)
	if err != nil {
		return fmt.Errorf("%w: %w", errdefs.ErrCheckNamespaceExists, err)
	}
	section.RealmContainerdNamespaceExistsPost = nsExistsPost

	section.RealmCreated = !section.RealmMetadataExistsPre && section.RealmMetadataExistsPost
	section.RealmContainerdNamespaceCreated = !section.RealmContainerdNamespaceExistsPre &&
		section.RealmContainerdNamespaceExistsPost
	section.RealmCgroupCreated = !section.RealmCgroupExistsPre && section.RealmCgroupExistsPost

	return nil
}

func (b *Exec) bootstrapSpace(section *SpaceSection, realmName, spaceName string) error {
	section.SpaceName = spaceName

	spaceDoc := &v1beta1.SpaceDoc{
		Metadata: v1beta1.SpaceMetadata{
			Name: spaceName,
			Labels: map[string]string{
				consts.KukeonRealmLabelKey: realmName,
				consts.KukeonSpaceLabelKey: spaceName,
			},
		},
		Spec: v1beta1.SpaceSpec{
			RealmID: realmName,
		},
	}

	lookupSpace := intmodel.Space{
		Metadata: intmodel.SpaceMetadata{
			Name: spaceName,
		},
		Spec: intmodel.SpaceSpec{
			RealmName: realmName,
		},
	}

	internalSpacePre, err := b.runner.GetSpace(lookupSpace)
	if err != nil {
		if errors.Is(err, errdefs.ErrSpaceNotFound) {
			section.SpaceMetadataExistsPre = false
		} else {
			return fmt.Errorf("%w: %w", errdefs.ErrGetSpace, err)
		}
	} else {
		section.SpaceMetadataExistsPre = true
		cgroupExists, cgroupErr := b.runner.ExistsCgroup(internalSpacePre)
		if cgroupErr != nil {
			return fmt.Errorf("failed to check if space cgroup exists: %w", cgroupErr)
		}
		section.SpaceCgroupExistsPre = cgroupExists
	}

	exists, err := b.runner.ExistsSpaceCNIConfig(lookupSpace)
	if err != nil {
		return fmt.Errorf("%w: %w", errdefs.ErrCheckNetworkExists, err)
	}
	section.SpaceCNINetworkExistsPre = exists

	space, _, err := apischeme.NormalizeSpace(*spaceDoc)
	if err != nil {
		return fmt.Errorf("%w: %w", errdefs.ErrConversionFailed, err)
	}

	spaceNet, err := naming.BuildSpaceNetworkName(space.Spec.RealmName, spaceName)
	if err != nil {
		return fmt.Errorf("%w: %w", errdefs.ErrConfig, err)
	}
	section.SpaceCNINetworkName = spaceNet

	if section.SpaceMetadataExistsPre {
		if _, err = b.runner.EnsureSpace(internalSpacePre); err != nil {
			return fmt.Errorf("%w: %w", errdefs.ErrCreateSpace, err)
		}
	} else {
		if _, err = b.runner.CreateSpace(space); err != nil {
			return fmt.Errorf("%w: %w", errdefs.ErrCreateSpace, err)
		}
	}

	internalSpacePost, err := b.runner.GetSpace(lookupSpace)
	if err != nil {
		if errors.Is(err, errdefs.ErrSpaceNotFound) {
			section.SpaceMetadataExistsPost = false
		} else {
			return fmt.Errorf("%w: %w", errdefs.ErrGetSpace, err)
		}
	} else {
		section.SpaceMetadataExistsPost = true
		cgroupExists, cgroupErr := b.runner.ExistsCgroup(internalSpacePost)
		if cgroupErr != nil {
			return fmt.Errorf("failed to check if space cgroup exists: %w", cgroupErr)
		}
		section.SpaceCgroupExistsPost = cgroupExists
	}
	exists, err = b.runner.ExistsSpaceCNIConfig(lookupSpace)
	if err != nil {
		return fmt.Errorf("%w: %w", errdefs.ErrCheckNetworkExists, err)
	}
	section.SpaceCNINetworkExistsPost = exists

	section.SpaceCreated = !section.SpaceMetadataExistsPre && section.SpaceMetadataExistsPost
	section.SpaceCNINetworkCreated = !section.SpaceCNINetworkExistsPre && section.SpaceCNINetworkExistsPost
	section.SpaceCgroupCreated = !section.SpaceCgroupExistsPre && section.SpaceCgroupExistsPost

	return nil
}

func (b *Exec) bootstrapStack(section *StackSection, realmName, spaceName, stackName string) error {
	section.StackName = stackName

	stackDoc := &v1beta1.StackDoc{
		Metadata: v1beta1.StackMetadata{
			Name: stackName,
			Labels: map[string]string{
				consts.KukeonRealmLabelKey: realmName,
				consts.KukeonSpaceLabelKey: spaceName,
				consts.KukeonStackLabelKey: stackName,
			},
		},
		Spec: v1beta1.StackSpec{
			ID:      stackName,
			RealmID: realmName,
			SpaceID: spaceName,
		},
	}

	lookupStackPre := intmodel.Stack{
		Metadata: intmodel.StackMetadata{
			Name: stackName,
		},
		Spec: intmodel.StackSpec{
			RealmName: realmName,
			SpaceName: spaceName,
		},
	}
	internalStackPre, err := b.runner.GetStack(lookupStackPre)
	if err != nil {
		if errors.Is(err, errdefs.ErrStackNotFound) {
			section.StackMetadataExistsPre = false
		} else {
			return fmt.Errorf("%w: %w", errdefs.ErrGetStack, err)
		}
	} else {
		section.StackMetadataExistsPre = true
		cgroupExists, cgroupErr := b.runner.ExistsCgroup(internalStackPre)
		if cgroupErr != nil {
			return fmt.Errorf("failed to check if stack cgroup exists: %w", cgroupErr)
		}
		section.StackCgroupExistsPre = cgroupExists
	}

	stack, _, err := apischeme.NormalizeStack(*stackDoc)
	if err != nil {
		return fmt.Errorf("%w: %w", errdefs.ErrConversionFailed, err)
	}

	if section.StackMetadataExistsPre {
		if _, err = b.runner.EnsureStack(internalStackPre); err != nil {
			return fmt.Errorf("%w: %w", errdefs.ErrCreateStack, err)
		}
	} else {
		if _, err = b.runner.CreateStack(stack); err != nil {
			return fmt.Errorf("%w: %w", errdefs.ErrCreateStack, err)
		}
	}

	lookupStackPost := intmodel.Stack{
		Metadata: intmodel.StackMetadata{
			Name: stack.Metadata.Name,
		},
		Spec: intmodel.StackSpec{
			RealmName: stack.Spec.RealmName,
			SpaceName: stack.Spec.SpaceName,
		},
	}
	internalStackPost, err := b.runner.GetStack(lookupStackPost)
	if err != nil {
		if errors.Is(err, errdefs.ErrStackNotFound) {
			section.StackMetadataExistsPost = false
		} else {
			return fmt.Errorf("%w: %w", errdefs.ErrGetStack, err)
		}
	} else {
		section.StackMetadataExistsPost = true
		cgroupExists, cgroupErr := b.runner.ExistsCgroup(internalStackPost)
		if cgroupErr != nil {
			return fmt.Errorf("failed to check if stack cgroup exists: %w", cgroupErr)
		}
		section.StackCgroupExistsPost = cgroupExists
	}

	section.StackCreated = !section.StackMetadataExistsPre && section.StackMetadataExistsPost
	section.StackCgroupCreated = !section.StackCgroupExistsPre && section.StackCgroupExistsPost

	return nil
}

// kukeondCellDoc builds the CellDoc describing the kukeond system cell.
// The host runPath is bind-mounted into the container at the same path and
// passed via --run-path so that kukeond reads/writes the same metadata store
// that kuke uses in --no-daemon mode. The host containerd socket directory is
// also bind-mounted and --containerd-socket is forwarded so kukeond can reach
// the same containerd daemon as kuke does on the host. The host cgroup2
// hierarchy at /sys/fs/cgroup is bind-mounted so kukeond can create the
// realm/space/stack/cell cgroup tree for user workloads — without it, the
// daemon container only sees a fresh read-only sysfs and cgroup creation
// returns ENOENT. Pinned alongside that bind-mount, HostCgroup=true on the
// kukeond container opts it into its parent's cgroup namespace so its view
// of /sys/fs/cgroup matches the host layout — with cgroup-ns private (the
// default for user workloads), kukeond's cgroup root would re-anchor at its
// own cell and sibling-cgroup creation under /kukeon/<realm>/... would
// resolve against the wrong subtree. The two pieces (host bind-mount + host
// cgroup-ns) are the kukeond cgroup carve-out and only make sense together.
// The host containerd data root at /var/lib/containerd is
// bind-mounted as well: kukeond performs in-process overlay mounts during
// container creation (image unpack, image-config resolution) that reference
// snapshot lowerdirs under that tree, and the mount syscalls execute in the
// daemon container's mount namespace — without the bind-mount the kernel
// returns ENOENT on the host paths. CNI state lives on the host too: the
// conflists at /opt/cni/net.d are written by kuke init's in-process bootstrap
// and have to be readable by the daemon on later applies; /var/lib/cni holds
// host-local IPAM state, which daemon and --no-daemon must share so they
// don't allocate the same IP twice; /opt/cni/cache holds the CNI invocation
// cache that gives DEL stable arguments — a mismatch leaks veths and IPs
// across daemon restarts.
func kukeondCellDoc(
	image, socketPath, runPath, containerdSocket string,
	socketGID int,
	configurationPath string,
) *v1beta1.CellDoc {
	args := []string{"serve", "--socket", socketPath}
	// `kukeond` (the cobra root) processes --configuration in PersistentPreRunE,
	// so the flag must come before the `serve` subcommand on the cell args. Cobra
	// is permissive about positional ordering, but listing the persistent flag
	// first matches what the operator types on the host shell.
	if configurationPath != "" {
		args = append([]string{"--configuration", configurationPath}, args...)
	}
	if runPath != "" {
		args = append(args, "--run-path", runPath)
	}
	if containerdSocket != "" {
		args = append(args, "--containerd-socket", containerdSocket)
	}
	if socketGID > 0 {
		args = append(args, "--socket-gid", strconv.Itoa(socketGID))
	}

	sockDir := socketDir(socketPath)
	volumes := []v1beta1.VolumeMount{
		{Source: sockDir, Target: sockDir},
		{Source: "/sys/fs/cgroup", Target: "/sys/fs/cgroup"},
		{Source: "/var/lib/containerd", Target: "/var/lib/containerd"},
		{Source: "/opt/cni/net.d", Target: "/opt/cni/net.d"},
		{Source: "/var/lib/cni", Target: "/var/lib/cni"},
		{Source: "/opt/cni/cache", Target: "/opt/cni/cache"},
	}
	if runPath != "" && runPath != sockDir {
		volumes = append(volumes, v1beta1.VolumeMount{Source: runPath, Target: runPath})
	}
	if containerdSocket != "" {
		ctrdDir := socketDir(containerdSocket)
		if ctrdDir != sockDir && ctrdDir != runPath {
			volumes = append(volumes, v1beta1.VolumeMount{Source: ctrdDir, Target: ctrdDir})
		}
	}
	if configurationPath != "" {
		cfgDir := socketDir(configurationPath)
		if !volumeContainsTarget(volumes, cfgDir) {
			volumes = append(volumes, v1beta1.VolumeMount{Source: cfgDir, Target: cfgDir})
		}
	}

	return &v1beta1.CellDoc{
		Metadata: v1beta1.CellMetadata{
			Name: consts.KukeSystemCellName,
			Labels: map[string]string{
				consts.KukeonRealmLabelKey: consts.KukeSystemRealmName,
				consts.KukeonSpaceLabelKey: consts.KukeSystemSpaceName,
				consts.KukeonStackLabelKey: consts.KukeSystemStackName,
				consts.KukeonCellLabelKey:  consts.KukeSystemCellName,
			},
		},
		Spec: v1beta1.CellSpec{
			ID:      consts.KukeSystemCellName,
			RealmID: consts.KukeSystemRealmName,
			SpaceID: consts.KukeSystemSpaceName,
			StackID: consts.KukeSystemStackName,
			Containers: []v1beta1.ContainerSpec{
				{
					ID:      consts.KukeSystemContainerName,
					RealmID: consts.KukeSystemRealmName,
					SpaceID: consts.KukeSystemSpaceName,
					StackID: consts.KukeSystemStackName,
					CellID:  consts.KukeSystemCellName,
					Image:   image,
					Command: "/bin/kukeond",
					Args:    args,
					Volumes: volumes,
					// kukeond orchestrates host-level networking (CNI bridges,
					// veths, iptables MASQUERADE rules) — those need host
					// scope, not the daemon's own netns. The cell's
					// auto-default root container inherits HostNetwork from
					// any HostNetwork=true workload in the cell, so kukeond
					// (which joins the root's netns) ends up on the host.
					HostNetwork: true,
					// HostPID is needed by the CNI bridge plugin running
					// inside kukeond: when it attaches a *user* cell to a
					// network it receives the user-cell's root PID from
					// containerd's task.Pid(), which is a *host* PID. With
					// kukeond's own PID namespace, /proc/<host-pid>/ns/net
					// returns ENOENT and the attach fails. HostPID=true
					// drops the PID LinuxNamespace entry from kukeond's OCI
					// spec so /proc inside the daemon reflects host PIDs.
					// Distinct from HostNetwork — that fixed where kukeond's
					// own iptables/bridges land; this fixes how kukeond
					// resolves *other* containers' netns paths.
					HostPID: true,
					// HostCgroup keeps kukeond in its parent's cgroup
					// namespace so its view of /sys/fs/cgroup matches the
					// host layout — required because kukeond writes
					// sibling cgroups under /kukeon/<realm>/... that live
					// *outside* its own cell's subtree. With cgroup-ns
					// private (the default), kukeond's cgroup root would
					// re-anchor at its own cell and those writes would
					// resolve against the wrong subtree. Pinned alongside
					// the /sys/fs/cgroup host bind-mount in the volumes
					// list above; the two are the kukeond cgroup carve-out.
					HostCgroup: true,
					Privileged: true,
				},
			},
		},
	}
}

// ensureSocketDir creates the parent directory of the kukeond unix socket so
// that the bind-mount into the kukeond container has a source to mount.
func ensureSocketDir(socketPath string) error {
	dir := socketDir(socketPath)
	if err := os.MkdirAll(dir, 0o750); err != nil {
		return fmt.Errorf("create kukeond socket dir %q: %w", dir, err)
	}
	return nil
}

// ensureCNIStateDir creates /var/lib/cni so the kukeond cell's bind-mount has
// a source. host-local IPAM only creates /var/lib/cni/networks/<net>/ on its
// first allocation, which happens after the daemon is up — by then the cell
// would have already failed to start with ENOENT on the bind source. The two
// other CNI mounts (/opt/cni/net.d and /opt/cni/cache) are already created by
// the earlier CNI bootstrap step.
func ensureCNIStateDir() error {
	if err := os.MkdirAll("/var/lib/cni", 0o750); err != nil {
		return fmt.Errorf("create CNI state dir %q: %w", "/var/lib/cni", err)
	}
	// MkdirAll is a no-op when the dir already exists, so on upgrade from a
	// prior install (or co-existing CNI installer) that left /var/lib/cni at
	// 0o755, the mode would stay loose. Chmod here makes the tightening
	// idempotent across upgrades.
	if err := os.Chmod("/var/lib/cni", 0o750); err != nil {
		return fmt.Errorf("chmod CNI state dir %q: %w", "/var/lib/cni", err)
	}
	return nil
}

// volumeContainsTarget reports whether vols already binds-into target. Used to
// dedupe overlapping bind-mounts (e.g. /etc/kukeon being the same as another
// path that the runtime already exposes to the daemon container).
func volumeContainsTarget(vols []v1beta1.VolumeMount, target string) bool {
	for _, v := range vols {
		if v.Target == target {
			return true
		}
	}
	return false
}

// ensureServerConfigurationDir creates the parent dir of the ServerConfiguration
// path so the kukeond cell's bind-mount has a source. The file itself is
// optional — kukeond's loader treats an absent file as "use defaults" — but
// the directory must exist for the bind-mount to succeed.
func ensureServerConfigurationDir(configurationPath string) error {
	if configurationPath == "" {
		return nil
	}
	dir := socketDir(configurationPath)
	if err := os.MkdirAll(dir, 0o750); err != nil {
		return fmt.Errorf("create server configuration dir %q: %w", dir, err)
	}
	return nil
}

// socketDir returns the parent directory of the kukeond unix socket path.
func socketDir(socketPath string) string {
	for i := len(socketPath) - 1; i >= 0; i-- {
		if socketPath[i] == '/' {
			if i == 0 {
				return "/"
			}
			return socketPath[:i]
		}
	}
	return "/run/kukeon"
}

func (b *Exec) bootstrapCell(section *CellSection, cellDoc *v1beta1.CellDoc) error {
	section.CellName = cellDoc.Metadata.Name

	cell, _, err := apischeme.NormalizeCell(*cellDoc)
	if err != nil {
		return fmt.Errorf("%w: %w", errdefs.ErrConversionFailed, err)
	}

	lookupCellPre := intmodel.Cell{
		Metadata: intmodel.CellMetadata{
			Name: cell.Metadata.Name,
		},
		Spec: intmodel.CellSpec{
			RealmName: cell.Spec.RealmName,
			SpaceName: cell.Spec.SpaceName,
			StackName: cell.Spec.StackName,
		},
	}
	internalCellPre, err := b.runner.GetCell(lookupCellPre)
	if err != nil {
		if errors.Is(err, errdefs.ErrCellNotFound) {
			section.CellMetadataExistsPre = false
		} else {
			return fmt.Errorf("%w: %w", errdefs.ErrGetCell, err)
		}
	} else {
		section.CellMetadataExistsPre = true
		cgroupExists, cgroupErr := b.runner.ExistsCgroup(internalCellPre)
		if cgroupErr != nil {
			return fmt.Errorf("failed to check if cell cgroup exists: %w", cgroupErr)
		}
		section.CellCgroupExistsPre = cgroupExists
		rootExistsPre, rootErr := b.runner.ExistsCellRootContainer(internalCellPre)
		if rootErr != nil {
			return fmt.Errorf("failed to check if root container exists: %w", rootErr)
		}
		section.CellRootContainerExistsPre = rootExistsPre
		// Probe whether the cell's containers were already running before the
		// EnsureCell+StartCell pass below. GetCell populated live container
		// statuses off containerd, so this distinguishes a healthy idempotent
		// re-run (containers already up → StartCell is a no-op, report "already
		// running") from a re-run after a crash/stop (containers down → StartCell
		// genuinely transitions them, report "started"). Without this the phase
		// always reported a bare "started", misstating a no-op re-run as a
		// (re)start of the daemon's containers. Issue #1186. The image-drift
		// recreate branch overrides this back to false below — there the running
		// containers are torn down and rebuilt, so "started" is the correct
		// wording even though they were running pre.
		section.CellStartedPre = cellContainersRunning(internalCellPre)
	}

	// When the cell record survives from a prior `kuke init` (or a
	// `kuke daemon reset` that didn't actually purge it) and the operator
	// re-runs init against a freshly built image, the persisted root
	// container spec must be reconciled against the desired one — otherwise
	// EnsureCell+StartCell below would happily restart the stale image and
	// leave the running daemon binary frozen on the previous build. Issue
	// #868. The drift comparison is keyed on the canonical kukeond container
	// ID; a missing match on either side counts as drift so a corrupted /
	// partial cell record forces a recreate rather than a half-baked ensure.
	//
	// Layer 1 (#868): ref-string comparison — catches `kuke init` with a
	// different --kukeond-image value against the persisted cell.
	// Layer 2 (#915 defect 2): chainID comparison — catches the common
	// `make dev-init` re-run case where the ref string is unchanged but
	// `kuke build` re-pointed the same tag at fresh content. The ref-string
	// match would otherwise mask the swap, and EnsureCell+StartCell would
	// restart the same anchored snapshot.
	imageDrift := false
	if section.CellMetadataExistsPre {
		section.CellPriorImage = lookupContainerImage(internalCellPre, consts.KukeSystemContainerName)
		desiredImage := lookupContainerImage(cell, consts.KukeSystemContainerName)
		switch {
		case section.CellPriorImage != desiredImage:
			imageDrift = true
		case section.CellRootContainerExistsPre && desiredImage != "":
			drifted, dErr := b.kukeondContainerImageDigestDrifted(cell, desiredImage)
			if dErr != nil {
				// A probe failure (containerd unreachable, image absent,
				// snapshot key missing) is not fatal — fall through to
				// the EnsureCell+StartCell path so init can still bring
				// the daemon up. Surface the reason so an operator can
				// diagnose if the next iteration also reports drift.
				b.logger.WarnContext(b.ctx,
					"image digest drift probe failed; falling through to existing-cell path",
					"cell", cell.Metadata.Name,
					"image", desiredImage,
					"error", dErr,
				)
			} else if drifted {
				imageDrift = true
			}
		}
	}

	var ensuredCell intmodel.Cell
	startCellAfterEnsure := true
	switch {
	case imageDrift:
		// RecreateCell stops + deletes the stale root container, rebuilds it
		// against the desired spec, and runs StartCell internally — so the
		// post-switch StartCell below is suppressed to avoid a redundant
		// start cycle.
		ensuredCell, err = b.runner.RecreateCell(cell)
		if err != nil {
			return fmt.Errorf("recreate kukeond cell on image drift: %w", err)
		}
		section.CellRecreatedDueToImageDrift = true
		startCellAfterEnsure = false
		// RecreateCell tore down the running container and started a fresh one,
		// so the container-start phase genuinely transitioned — render "started",
		// not "already running", regardless of the pre-StartCell probe. Issue
		// #1186.
		section.CellStartedPre = false
	case section.CellMetadataExistsPre:
		ensuredCell, err = b.runner.EnsureCell(internalCellPre)
		if err != nil {
			return fmt.Errorf("%w: %w", errdefs.ErrCreateCell, err)
		}
	default:
		ensuredCell, err = b.runner.CreateCell(cell)
		if err != nil {
			return fmt.Errorf("%w: %w", errdefs.ErrCreateCell, err)
		}
	}

	if startCellAfterEnsure {
		if _, err = b.runner.StartCell(ensuredCell); err != nil {
			return fmt.Errorf("failed to start cell containers: %w", err)
		}
	}

	lookupCellPost := intmodel.Cell{
		Metadata: intmodel.CellMetadata{
			Name: cell.Metadata.Name,
		},
		Spec: intmodel.CellSpec{
			RealmName: cell.Spec.RealmName,
			SpaceName: cell.Spec.SpaceName,
			StackName: cell.Spec.StackName,
		},
	}
	internalCellPost, err := b.runner.GetCell(lookupCellPost)
	if err != nil {
		if errors.Is(err, errdefs.ErrCellNotFound) {
			section.CellMetadataExistsPost = false
		} else {
			return fmt.Errorf("%w: %w", errdefs.ErrGetCell, err)
		}
	} else {
		section.CellMetadataExistsPost = true
		cgroupExists, cgroupErr := b.runner.ExistsCgroup(internalCellPost)
		if cgroupErr != nil {
			return fmt.Errorf("failed to check if cell cgroup exists: %w", cgroupErr)
		}
		section.CellCgroupExistsPost = cgroupExists
		rootExistsPost, rootErr := b.runner.ExistsCellRootContainer(internalCellPost)
		if rootErr != nil {
			return fmt.Errorf("failed to check if root container exists: %w", rootErr)
		}
		section.CellRootContainerExistsPost = rootExistsPost
		section.CellStartedPost = true
	}

	section.CellCreated = !section.CellMetadataExistsPre && section.CellMetadataExistsPost
	section.CellCgroupCreated = !section.CellCgroupExistsPre && section.CellCgroupExistsPost
	// On the image-drift recreate branch the persisted record survived
	// (CellMetadataExistsPre stays true) but the root container itself was
	// torn down and rebuilt under the new image — surface that as "created"
	// rather than "already existed" so printContainerAction renders the
	// rebuild instead of misleading the operator into thinking the stale
	// container was re-used.
	if section.CellRecreatedDueToImageDrift {
		section.CellRootContainerCreated = true
	} else {
		section.CellRootContainerCreated = !section.CellRootContainerExistsPre &&
			section.CellRootContainerExistsPost
	}
	section.CellStarted = !section.CellStartedPre && section.CellStartedPost

	return nil
}

// cellContainersRunning reports whether every container in the cell's spec is
// observed running in the cell's populated live status. It mirrors the runner's
// cellTasksAllRunningFn idempotency guard (issue #149): StartCell no-ops only
// when every task is already running, so the bootstrap container-start phase
// must report "already running" rather than "started" exactly in that case
// (issue #1186). An empty container spec returns false — there is nothing whose
// running-ness could make StartCell a no-op. A spec container missing from the
// status slice (or in any non-running state) returns false so a partial /
// stopped cell renders "started" once StartCell transitions it.
func cellContainersRunning(cell intmodel.Cell) bool {
	if len(cell.Spec.Containers) == 0 {
		return false
	}
	for _, spec := range cell.Spec.Containers {
		if !containerStatusRunning(spec.ID, cell.Status.Containers) {
			return false
		}
	}
	return true
}

// containerStatusRunning reports whether the status carrying id is in a running
// state. Only ContainerStateReady counts — that is the intmodel mapping of
// containerd.Running, the state cellTasksAllRunningFn tests, so the
// "already running" verdict tracks StartCell's no-op condition exactly. A
// missing id (status not populated) is treated as not-running.
func containerStatusRunning(id string, statuses []intmodel.ContainerStatus) bool {
	for i := range statuses {
		if statuses[i].ID == id {
			return statuses[i].State == intmodel.ContainerStateReady
		}
	}
	return false
}

// lookupContainerImage returns the Image of the container in cell whose ID
// matches containerID. An empty string signals either "container not present"
// or "container present but image empty" — both count as drift against any
// non-empty desired image in bootstrapCell's comparison.
func lookupContainerImage(cell intmodel.Cell, containerID string) string {
	for _, c := range cell.Spec.Containers {
		if c.ID == containerID {
			return c.Image
		}
	}
	return ""
}

// kukeondContainerImageDigestDrifted reports whether the running kukeond
// container's anchored snapshot chain differs from the chain the image at
// the desired ref would unpack to today. The probe is only meaningful
// after the ref-string comparison has returned equal — equal ref + diverging
// chainID is exactly the shape `kuke build` re-pointing the same tag at
// fresh content produces (issue #915 defect 2), and the verifier at
// scripts/dev-init.sh:332-384 already encodes the equivalent shell-level
// check post-init.
//
// A probe error (containerd unreachable, image absent, snapshot key
// missing) returns drifted=false plus the wrapped error so the caller can
// log and fall through — init must still be able to bring the daemon up
// from a degraded inspect path; the ref-string-equal path was the
// pre-issue-#915 default and is the safe fallback.
func (b *Exec) kukeondContainerImageDigestDrifted(
	cell intmodel.Cell, desiredImage string,
) (bool, error) {
	namespace := consts.RealmNamespace(cell.Spec.RealmName)
	containerdID, err := naming.BuildContainerdID(
		cell.Spec.SpaceName, cell.Spec.StackName, cell.Metadata.Name, consts.KukeSystemContainerName,
	)
	if err != nil {
		return false, fmt.Errorf("build kukeond containerd id: %w", err)
	}
	containerChainID, err := b.runner.ContainerRootChainID(namespace, containerdID)
	if err != nil {
		return false, fmt.Errorf("read kukeond snapshot chain (%s/%s): %w", namespace, containerdID, err)
	}
	imageChainID, err := b.runner.ImageChainID(namespace, desiredImage)
	if err != nil {
		return false, fmt.Errorf("read image chain (%s/%s): %w", namespace, desiredImage, err)
	}
	// An empty chainID on either side means "no comparable identity" —
	// e.g. an image with zero layers, or a snapshot the snapshotter
	// reports with no parent. Treat as no drift so the existing-cell
	// path still runs; the alternative would be perpetual recreate
	// loops on edge-case content.
	if containerChainID == "" || imageChainID == "" {
		return false, nil
	}
	return containerChainID != imageChainID, nil
}

func (b *Exec) bootstrapCNI(report BootstrapReport) (BootstrapReport, error) {
	cniRep, err := b.runner.BootstrapCNI("", "", "")
	if err != nil {
		return report, err
	}
	report.CniConfigDir = cniRep.CniConfigDir
	report.CniCacheDir = cniRep.CniCacheDir
	report.CniBinDir = cniRep.CniBinDir
	report.CniConfigDirExistsPre = cniRep.ConfigDirExistsPre
	report.CniCacheDirExistsPre = cniRep.CacheDirExistsPre
	report.CniBinDirExistsPre = cniRep.BinDirExistsPre
	report.CniConfigDirCreated = cniRep.ConfigDirCreated
	report.CniCacheDirCreated = cniRep.CacheDirCreated
	report.CniBinDirCreated = cniRep.BinDirCreated
	report.CniConfigDirExistsPost = cniRep.ConfigDirExistsPost
	report.CniCacheDirExistsPost = cniRep.CacheDirExistsPost
	report.CniBinDirExistsPost = cniRep.BinDirExistsPost
	return report, nil
}
