package dockerfile

import (
	"context"
	"log/slog"

	"github.com/alexei/tinyforge/internal/store"
	"github.com/alexei/tinyforge/internal/workload/plugin"
)

// reconcile syncs the container row's state column with Docker reality
// for this workload's single container, and marks the runtime state as
// "failed" if the container is gone or has crashed. Same shape as the
// static plugin's reconcile — minimal, no automatic re-build on a
// missing container. The dashboard surfaces the failed status; the
// operator triggers redeploy explicitly.
//
// Auto-redeploy could be added later, but it should be gated on a
// per-workload toggle: a crash loop with auto-rebuild would burn CPU
// rebuilding the same broken commit forever.
func reconcile(ctx context.Context, deps plugin.Deps, w plugin.Workload) error {
	st, prevContainer, err := loadState(deps, w)
	if err != nil {
		return err
	}
	if prevContainer == nil || prevContainer.ContainerID == "" {
		return nil
	}

	running, err := deps.Docker.IsContainerRunning(ctx, prevContainer.ContainerID)
	if err != nil {
		// Most likely "no such container" — mark missing so the UI
		// surfaces it; runtime status moves to "failed" so the
		// dashboard and operator event triggers see the regression.
		if uerr := deps.Store.UpdateContainerState(prevContainer.ID, "missing"); uerr != nil {
			slog.Warn("dockerfile: mark missing", "workload", w.Name, "error", uerr)
		}
		if st.Status == "deployed" {
			if uerr := saveState(deps, w, func(rs *runtimeState, c *store.Container) {
				rs.Status = "failed"
				rs.LastError = "container not found"
				c.State = "missing"
			}); uerr != nil {
				slog.Warn("dockerfile: persist missing-state", "workload", w.Name, "error", uerr)
			}
			publishEvent(deps, w, "failed: container not found")
		}
		return nil
	}

	desired := "running"
	if !running {
		desired = "stopped"
	}
	if prevContainer.State != desired {
		if err := deps.Store.UpdateContainerState(prevContainer.ID, desired); err != nil {
			slog.Warn("dockerfile: state sync", "workload", w.Name, "error", err)
		}
	}

	if !running && st.Status == "deployed" {
		if err := saveState(deps, w, func(rs *runtimeState, c *store.Container) {
			rs.Status = "failed"
			rs.LastError = "container stopped unexpectedly"
			c.State = "stopped"
		}); err != nil {
			slog.Warn("dockerfile: persist crashed-state", "workload", w.Name, "error", err)
		}
		publishEvent(deps, w, "failed: container stopped unexpectedly")
	}
	return nil
}
