package inc

import (
	inkwell "git.teletypegames.org/engines/inkwell"
)

func (w *world) Do(a inkwell.Action) {
	if a != nil {
		w.queue = append(w.queue, a)
	}
}

func (w *world) PumpTick(dt float64) {
	if w.running == nil {
		if len(w.queue) == 0 {
			return
		}
		w.running = w.queue[0].Start()
		w.queue = w.queue[1:]
	}
	ctx := &inkwell.Ctx{
		Game: w.G,
		DT:   dt,
	}
	if s, ok := w.G.SceneManager.Get(w.G.CurrentScene()); ok {
		ctx.Scene = &s
	}
	if w.running.Tick(ctx) != inkwell.StatusRunning {
		w.running = nil
	}
}

func (w *world) SceneTitle() string {
	s, ok := w.G.SceneManager.Get(w.G.CurrentScene())
	if !ok {
		return ""
	}
	if s.Title != "" {
		return s.Title
	}
	return s.Name
}

type fnAction struct{ fn func(*inkwell.Ctx) }

func (a *fnAction) Start() inkwell.Runner {
	return &fnRunner{
		spec: a,
	}
}

type fnRunner struct{ spec *fnAction }

func (r *fnRunner) Tick(ctx *inkwell.Ctx) inkwell.Status {
	r.spec.fn(ctx)
	return inkwell.StatusDone
}

func Fn(f func(*inkwell.Ctx)) inkwell.Action {
	return &fnAction{
		fn: f,
	}
}

func UseTheme(name string) inkwell.Action {
	return Fn(func(ctx *inkwell.Ctx) { ctx.Game.UseTheme(name) })
}

func SetMode(m Mode) inkwell.Action {
	return Fn(func(*inkwell.Ctx) { World.SetMode(m) })
}

func TapeSay(speaker, text string) inkwell.Action {
	return &tapeSayAction{
		speaker: speaker,
		text:    text,
	}
}

type tapeSayAction struct{ speaker, text string }

func (a *tapeSayAction) Start() inkwell.Runner {
	return &tapeSayRunner{
		spec: a,
	}
}

type tapeSayRunner struct {
	spec     *tapeSayAction
	started  bool
	elapsed  float64
	duration float64
}

func (r *tapeSayRunner) Tick(ctx *inkwell.Ctx) inkwell.Status {
	if !r.started {
		r.started = true

		r.duration = 1.2 + float64(len([]rune(r.spec.text)))*0.05
		ctx.Game.LogResponse(r.spec.speaker, r.spec.text)
	}
	r.elapsed += ctx.DT
	if r.elapsed >= r.duration {
		return inkwell.StatusDone
	}
	return inkwell.StatusRunning
}

func TapeOffer(line inkwell.Action) inkwell.Action {
	return Fn(func(*inkwell.Ctx) {
		World.tapeLine = line
		World.tapeWaiting = true
	})
}

func (w *world) TakeTapeOffer() {
	if !w.tapeWaiting {
		return
	}
	w.tapeWaiting = false
	line := w.tapeLine
	w.tapeLine = nil
	w.Do(line)
}

func Paused(inner inkwell.Action) inkwell.Action {
	return &pausedAction{
		inner: inner,
	}
}

type pausedAction struct {
	inner inkwell.Action
}

func (a *pausedAction) Start() inkwell.Runner {
	return &pausedRunner{
		spec:  a,
		inner: a.inner.Start(),
	}
}

type pausedRunner struct {
	spec    *pausedAction
	inner   inkwell.Runner
	started bool
}

func (r *pausedRunner) Tick(ctx *inkwell.Ctx) inkwell.Status {
	if !r.started {
		r.started = true
		World.paused = true
	}
	s := r.inner.Tick(ctx)
	if s != inkwell.StatusRunning {
		World.paused = false
	}
	return s
}
