package main

import (
	
	
	

	
	
	

	
	amhelp 
	am 
)

var ss = states.TuiStates

func init() {
	_ = godotenv.Load()
}

func main() {
	 := context.Background()

	 := &tui{}
	,  := am.NewCommon(, "tui", states.TuiSchema, ss.Names(),
		, nil, nil)
	if  != nil {
		panic()
	}
	.Mach = 
	amhelp.MachDebugEnv()
	.Add1(ss.Start, nil)
	<-.WhenNot1(ss.Start, nil)

	time.Sleep(time.Second)
}

// TUI

type tui struct {
	*am.ExceptionHandler

	Mach *am.Machine
	App  *cview.Application
	// UI is currently being drawn
	drawing atomic.Bool
	// repaintScheduled controls the UI paint debounce
	repaintScheduled atomic.Bool
	// repaintPending indicates a skipped repaint
	repaintPending atomic.Bool

	// go -race flag passed
	DbgRace bool
}

// handlers

func ( *tui) ( *am.Event) {
	// cview TUI app
	.App = cview.NewApplication()
	.App.EnableMouse(true)

	// forceful race solving
	.App.SetBeforeDrawFunc(func( tcell.Screen) bool {
		// dont draw while transitioning
		 := .Mach.Transition() == nil
		if ! {
			// reschedule this repaint
			// d.Mach.Log("postpone draw")
			.repaintPending.Store(true)
			return true
		}

		// mark as in progress
		.drawing.Store(true)
		return false
	})
	.App.SetAfterDrawFunc(func( tcell.Screen) {
		.drawing.Store(false)
	})
	.App.SetAfterResizeFunc(func( int,  int) {
		go func() {
			time.Sleep(time.Millisecond * 300)
			.Mach.Add1(ss.Resized, nil)
		}()
	})

	 := .Mach.NewStateCtx(ss.Start)

	// draw in a goroutine
	go func() {
		if .Err() != nil {
			return // expired
		}
		.Mach.PanicToErr(nil)

		.App.SetRoot(.initUi(), true)
		 := .App.Run()
		if  != nil {
			.Mach.AddErr(, nil)
		}

		.Mach.Dispose()
	}()

	// post-start ops
	go func() {
		if .Err() != nil {
			return // expired
		}

		// TODO
	}()
}

// AnyEnter prevents most of mutations during a UI redraw (and vice versa)
// forceful race solving
func ( *tui) ( *am.Event) bool {
	// always pass network traffic
	 := .Mach
	 := .Mutation()
	 := .CalledIndex(ss.Names())
	 := am.S{ss.IncomingData, am.StateException}
	if .Any1(...) {
		return true
	}

	// dont allow mutations while drawing, pull 10 times
	 := .HandlerTimeout / 10
	 := 100
	// compensate extended timeouts
	if amhelp.IsDebug() {
		 = 10 * time.Millisecond
	}
	for .IsValid() {
		 := !.drawing.Load()
		if  {
			// ok
			return true
		}

		// delay, but avoid the race detector which gets stuck here
		if !.DbgRace {
			time.Sleep()
		}

		--
		if  <= 0 {
			// not ok
			break
		}
	}

	// prepend this mutation to the queue and try again TODO loop guard
	// d.Mach.Log("postpone mut")
	go .PrependMut()

	return false
}

// AnyState is a global final handler
func ( *tui) ( *am.Event) {
	 := .Transition()

	// redraw on auto states
	// TODO this should be done better
	if .IsAuto() && .IsAccepted.Load() {
		.repaintPending.Store(false)
		.draw()
	} else if .repaintPending.Swap(false) {
		.draw()
	}
}

// methods

func ( *tui) ( ...cview.Primitive) {
	if !.repaintScheduled.CompareAndSwap(false, true) {
		return
	}

	go func() {
		select {
		case <-.Mach.Ctx().Done():
			return

		// debounce every 16msec
		case <-time.After(16 * time.Millisecond):
		}

		.App.QueueUpdateDraw(func() {
			.repaintScheduled.Store(false)
		}, ...)
	}()
}

func ( *tui) () cview.Primitive {
	 := func( string) cview.Primitive {
		 := cview.NewTextView()
		.SetTextAlign(cview.AlignCenter)
		.SetText()
		return 
	}
	 := ("Menu")
	 := ("Main content")
	 := ("Side Bar")

	 := cview.NewGrid()
	.SetRows(3, 0, 3)
	.SetColumns(30, 0, 30)
	.SetBorders(true)
	.AddItem(("Header"), 0, 0, 1, 3, 0, 0, false)
	.AddItem(("Footer"), 2, 0, 1, 3, 0, 0, false)

	// Layout for screens narrower than 100 cells (menu and side bar are hidden).
	.AddItem(, 0, 0, 0, 0, 0, 0, false)
	.AddItem(, 1, 0, 1, 3, 0, 0, false)
	.AddItem(, 0, 0, 0, 0, 0, 0, false)

	// Layout for screens wider than 100 cells.
	.AddItem(, 1, 0, 1, 1, 0, 100, false)
	.AddItem(, 1, 1, 1, 1, 0, 100, false)
	.AddItem(, 1, 2, 1, 1, 0, 100, false)

	return 
}