//go:build js && wasm

package wasmruntime

import (
	"syscall/js"

	"kjol/vdom"
)

// State preservation across an in-place hot swap (see the dev server's
// livereload script). A fresh wasm instance has fresh Go memory, so signal
// values would reset on every rebuild. To keep them, the outgoing instance
// snapshots its signals (by creation order, via a vdom.Collector) into
// sessionStorage on dispose, and the incoming instance restores them on boot.
//
// It's best-effort: if an edit adds/removes/reorders signals, the by-order match
// shifts and unmatched signals fall back to their initial value — the same
// hook-order caveat as server components.

const stateKey = "__gowasm_hmr_state"

var stateCollector *vdom.Collector

// PreserveState registers the collector whose signals are snapshotted to
// sessionStorage when this instance is disposed for a hot swap.
func PreserveState(c *vdom.Collector) { stateCollector = c }

// RestoreState returns the signal snapshot saved by a prior instance before a
// hot swap, or nil if there is none. It is one-shot: the entry is cleared so a
// manual page refresh starts from initial state.
func RestoreState() [][]byte {
	ss := js.Global().Get("sessionStorage")
	if !ss.Truthy() {
		return nil
	}
	raw := ss.Call("getItem", stateKey)
	if !raw.Truthy() {
		return nil
	}
	ss.Call("removeItem", stateKey)
	arr := js.Global().Get("JSON").Call("parse", raw)
	if arr.Type() != js.TypeObject {
		return nil
	}
	out := make([][]byte, arr.Length())
	for i := range out {
		out[i] = []byte(arr.Index(i).String())
	}
	return out
}

// saveState writes the preserved collector's current signal values to
// sessionStorage. Called from the dispose hook before the DOM is torn down.
func saveState() {
	if stateCollector == nil {
		return
	}
	ss := js.Global().Get("sessionStorage")
	if !ss.Truthy() {
		return
	}
	arr := js.Global().Get("Array").New()
	for _, b := range stateCollector.Snapshot() {
		arr.Call("push", string(b))
	}
	ss.Call("setItem", stateKey, js.Global().Get("JSON").Call("stringify", arr))
}
