package static

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 since the last
// deploy. Intentionally minimal — the legacy HealthChecker still
// services rows in the static_sites table, so we don't need to mirror
// its full behavior here. Future versions can re-deploy on a missing
// container; today we just keep the index honest.
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 the row missing so
		// the UI surfaces it; the runtime state's status moves to
		// "failed" so the dashboard does not falsely report deployed.
		if uerr := deps.Store.UpdateContainerState(prevContainer.ID, "missing"); uerr != nil {
			slog.Warn("static source: mark missing", "site", 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("static source: persist missing-state", "site", 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("static source: state sync", "site", w.Name, "error", err)
		}
	}

	// Keep runtime status honest: a deployed-then-crashed container
	// should report failed so the dashboard / event triggers fire.
	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("static source: persist crashed-state", "site", w.Name, "error", err)
		}
		publishEvent(deps, w, "failed: container stopped unexpectedly")
	}
	return nil
}
