// Resident hero policy (engine memory):
// - After the last WebSocket disconnect, the hero stays in Engine.movements; the world keeps ticking.
// - Cold start: ListHeroesForEngineBootstrap loads rows with ws_disconnected_at set (cap 500 default in main).
// - Full hero row is saved every offlineDisconnectedFullSaveInterval while heroSubscriber reports false.
package game

import (
	"context"
	"log/slog"
	"time"

	"github.com/denisovdennis/autohero/internal/model"
	"github.com/denisovdennis/autohero/internal/storage"
)

// BootstrapResidentHeroes loads heroes whose WebSocket session had ended before this process started,
// catches up wall time using the same batch path as server-downtime recovery, then registers them
// in the engine so movement and combat continue without a live subscriber.
func BootstrapResidentHeroes(ctx context.Context, e *Engine, heroStore *storage.HeroStore, sim *OfflineSimulator, logger *slog.Logger) {
	if e == nil || heroStore == nil || sim == nil {
		return
	}
	heroes, err := heroStore.ListHeroesForEngineBootstrap(ctx)
	if err != nil {
		if logger != nil {
			logger.Error("engine bootstrap: list heroes", "error", err)
		}
		return
	}
	now := time.Now()
	for _, h := range heroes {
		if h == nil {
			continue
		}
		e.mu.Lock()
		_, already := e.movements[h.ID]
		rg := e.roadGraph
		e.mu.Unlock()
		if already || rg == nil {
			continue
		}

		e.mergeTownSessionFromRedis(h)

		if err := sim.SimulateHeroAt(ctx, h, now, true); err != nil {
			if logger != nil {
				logger.Error("engine bootstrap: catch-up sim", "hero_id", h.ID, "error", err)
			}
			continue
		}

		e.mu.Lock()
		if e.roadGraph == nil {
			e.mu.Unlock()
			return
		}
		if _, taken := e.movements[h.ID]; taken {
			e.mu.Unlock()
			continue
		}
		hm := NewHeroMovement(h, e.roadGraph, now)
		e.movements[h.ID] = hm
		hm.MarkTownPausePersisted(hm.townPausePersistSignature())
		hm.SyncToHero()
		if hm.State == model.StateFighting {
			if _, exists := e.combats[h.ID]; !exists {
				en := PickEnemyForHero(h)
				if en.Slug != "" {
					e.startCombatLocked(hm.Hero, &en)
				} else {
					hm.State = model.StateWalking
					hm.Hero.State = model.StateWalking
				}
			}
		}
		e.mu.Unlock()

		if logger != nil {
			logger.Info("engine bootstrap: resident hero registered", "hero_id", h.ID)
		}
	}
}
