package visualizer

import (
	
	
	
	
	
	

	merascii 
	
	
	
	
	
	d2log 
	

	

	
	amhelp 
	am 
)

var ErrEmptyTx = errors.New("empty tx")

type Transition struct {
	Tx *dbg.DbgMsgTx
}

// D2 will generate a D2 sequence diagram and an SVG of a given transition.
func ( *Transition) (
	 context.Context,  *slog.Logger,  am.S,
) (string, []byte, error) {
	// TODO accept prev tx, show activity from prev tx

	if .Tx.Steps == nil {
		return "", nil, ErrEmptyTx
	}

	// TODO extract, add stats, time, source, add machine time
	 := ""
	 += "**[" + .Tx.Type.String() + "] " +
		utils.J(.Tx.CalledStateNames()) + "**\n\n"
	 += "- mach://" + .Tx.MachineID + "/" + .Tx.ID + "\n"
	 += "- " + .Tx.Time.UTC().Format(time.RFC3339Nano) + "\n"

	 := ""
	 := make(map[string]bool)
	 := am.S{}
	for ,  := range .Tx.Steps {
		 := strings.Split(.StringFromIndex(), " ")
		 := []string{}
		 := ""

		switch len() {

		// "activate Requesting"
		case 2:
			 = [0]
			 := [1]
			// handle "handler FooState" -> Foo
			if  == "handler" {
				// TODO func suffix? "FooState(e)"
				 = amhelp.HandlerToState()
				 +=  + " -> " +  + ": " + [1]
			} else {
				 +=  + " -> " +  + ": " + [0]
			}
			[] = true

		// "Foo require Bar"
		case 3:
			 += [0] + " -> " + [2] + ": " + [1]
			[[0]] = true
			[[2]] = true
			 = [1]

		default:
			// TODO err
			continue
		}

		// line style TODO extract, use enum
		switch  {
		case "handler":
			 = append(, `style.stroke: "#2596be"`)
		case "requested":
			fallthrough
		case "require":
			 = append(, "style.stroke: lightblue")
		case "activate":
			fallthrough
		case "add":
			 = append(, "style.stroke: green")
		case "deactivate":
			fallthrough
		case "deactivate-passive":
			fallthrough
		case "remove":
			 = append(, "style.stroke: orange")
		case "cancel":
			 = append(, "style.stroke: red", "style.stroke-width: 5")
		}
		if len() > 0 {
			 += " {\n\t" + strings.Join(, "\n\t") + "\n}\n"
		}

		 += "\n"
	}

	// clean up
	for  := range  {
		 = append(, strings.ReplaceAll(, "*", ""))
	}

	 := ""
	for ,  := range slices.Concat(, am.S{am.StateAny}) {
		if !slices.Contains(, ) {
			continue
		}
		 +=  + ".style: {stroke: grey}\n"
		// TODO add multi, called, activity from prev tx
		switch {
		case  == am.StateStart:
			if .Tx.Is1(, ) {
				 +=  + ".class: _1s\n"
			} else {
				 +=  + ".class: _0s\n"
			}
		case  == am.StateReady:
			if .Tx.Is1(, ) {
				 +=  + ".class: _1r\n"
			} else {
				 +=  + ".class: _0r\n"
			}
		case .Tx.Is1(, ):
			if IsStateInherited(, ) {
				 +=  + ".class: _1i\n"
			} else {
				 +=  + ".class: _1\n"
			}
		default:
			if IsStateInherited(, ) {
				 +=  + ".class: _0i\n"
			} else {
				 +=  + ".class: _0\n"
			}
		}
	}

	// D2 TODO style for states
	 := utils.Sp(`
		shape: sequence_diagram
		
		%s
		explanation: |md
			%s
		| {
			near: top-center
			style.font-size: 28
		}
		
		%s
		
		%s
		
		`, d2Header, strings.ReplaceAll(strings.ReplaceAll(,
		"\n", "\n\t"),
		"|", ""),
		,
		strings.ReplaceAll(, "*", ""))

	// svg
	,  := .d2Svg(, , )

	return , , 
}

func ( *Transition) (
	 context.Context,  string,  *slog.Logger,
) ([]byte, error) {
	// set up
	,  := textmeasure.NewRuler()
	 = d2log.With(, )
	, ,  := d2lib.Compile(, , &d2lib.CompileOptions{
		Ruler:          ,
		LayoutResolver: layoutResolver,
	}, &d2svg.RenderOpts{})
	if  != nil {
		return nil, 
	}

	// render
	,  := d2svg.Render(, &d2svg.RenderOpts{
		ThemeID: &d2themescatalog.DarkMauve.ID,
	})
	return , 
}

func ( *Transition) ( am.S) (string, string, error) {
	if .Tx.Steps == nil {
		return "", "", ErrEmptyTx
	}

	 := ""
	 := make(map[string]bool)
	 := am.S{}
	for ,  := range .Tx.Steps {
		 := strings.Split(.StringFromIndex(), " ")
		 := ""

		switch len() {

		// "activate Requesting"
		case 2:
			 = [0]
			 := [1]
			// handle "handler FooState" -> Foo
			if  == "handler" {
				 = amhelp.HandlerToState()
				 +=  + " ->> " +  + ": " + [1]
			} else {
				 +=  + " ->> " +  + ": " + [0]
			}
			[] = true

		// "Foo require Bar"
		case 3:
			 += "  " + [0] + " ->> " + [2] + ": " + [1]
			[[0]] = true
			[[2]] = true
			 = [1]

		default:
			// TODO err
			continue
		}

		// TODO line styles

		 += "\n"
	}

	// clean up
	for  := range  {
		 = append(, strings.ReplaceAll(, "*", ""))
	}

	 := ""
	for ,  := range slices.Concat(, am.S{am.StateAny}) {
		if !slices.Contains(, ) {
			continue
		}

		 += "participant " +  + "\n"
	}

	// mermaid
	 := utils.Sp(`
		sequenceDiagram
	
		%s
	
		%s
	`, , strings.ReplaceAll(, "*", ""))

	// ascii
	,  := merascii.Parse()
	if  != nil {
		return , "", 
	}
	,  := merascii.Render(, nil)

	return , , 
}

// ///// ///// /////

// ///// MISC

// ///// ///// /////

func layoutResolver( string) (d2graph.LayoutGraph, error) {
	return d2dagrelayout.DefaultLayout, nil
}