package repl

import (
	
	
	
	
	
	
	
	
	
	
	

	
	

	
	amhelp 
	am 
	ssrpc 
	ssam 
)

// TODO use utils.Sp for all multilines

type (
	S = am.S
	T = am.Time
)

var Sp = utils.Sp

var (
	title   = "aRPC REPL for asyncmachine.dev"
	example = Sp(`
	- REPL from an addr
	  $ arpc localhost:6452
	- REPL from a file
	  $ arpc -f mymach.addr
	- CLI add states with args
	  $ arpc localhost:6452 -- add mach1 Foo Bar \
	    --arg name1 --val val1
	- CLI add states with args to the first machine
		$ arpc localhost:6452 -- add . Foo Bar \
	    --arg name1 --val val1
	- CLI wait on 2 states to be active
	  $ arpc localhost:6452 -- when mach1 Foo Bar
	- CLI add states to a group of machines
	  $ arpc localhost:6452 -- group-add -r ma.\* Foo Bar
`)
)

func ( *Repl, ,  []string) *cobra.Command {
	// ROOT

	var  *cobra.Command

	// CLI
	 := &cobra.Command{
		Use:     "arpc ADDR",
		Short:   title,
		Args:    cobra.ExactArgs(1),
		Example: example,
	}

	// REPL
	 = &cobra.Command{
		Use:     "arpc ADDR",
		Short:   title,
		Args:    cobra.ExactArgs(1),
		Example: example,
		RunE: func( *cobra.Command,  []string) error {
			return rootRun(, , , , )
		},
	}

	// flags

	.Flags().BoolP("file", "f", false,
		"Load addresses from a file")
	.Flags().BoolP("dir", "d", false,
		"Load *.addr files from a directory")
	.Flags().BoolP("watch", "w", false,
		"Watch the addr file / dir for changes (EXPERIMENTAL)")
	.Flags().String("am-dbg-addr", "",
		"Connect this client to am-dbg")
	.Flags().Int("log-level", 0,
		"Log level, 0-5 (silent-everything)")
	// TODO --log-file

	// CLI only flags

	if len() > 0 || len() == 0 {
		.Flags().BoolP("req-all", "a", false,
			"Require all addrs to connect (CLI only)")
	}

	// GROUPS

	 := []*cobra.Group{
		{ID: "mutating", Title: "Mutations"},
		{ID: "waiting", Title: "Waiting"},
		{ID: "inspecting", Title: "Checking"},
		{ID: "repl", Title: "REPL"},
	}
	for ,  := range  {
		.AddGroup()
		.AddGroup()
	}

	// MUTATIONS

	 := MutationCmds()
	for ,  := range  {
		.AddCommand()
		.AddCommand()
	}

	// INSPECTING

	 = InspectingCmds()
	for ,  := range  {
		.AddCommand()
		.AddCommand()
	}

	// WAITING

	 = WaitingCmds()
	for ,  := range  {
		.AddCommand()
		.AddCommand()
	}

	// REPL

	 = SysCmds()
	for ,  := range  {
		.AddCommand()
		.AddCommand()
	}

	.SetHelpCommandGroupID("repl")

	return 
}

func rootRun(
	 *Repl,  *cobra.Command,  []string,  []string,
	 *cobra.Command,
) error {
	var  *fsnotify.Watcher
	var  []string
	 := .Mach

	// CLI mode
	 := len()

	// help screen
	if  == 0 {
		return nil
	}

	// flags
	,  := .Flags().GetBool("watch")
	if  != nil {
		return 
	}
	,  := .Flags().GetBool("dir")
	if  != nil {
		return 
	}
	,  := .Flags().GetBool("file")
	if  != nil {
		return 
	}

	// validate flags
	if  &&  {
		return fmt.Errorf("cannot use both --dir and --file")
	}
	if  && ! && ! {
		return fmt.Errorf("--file or --dir required for --watch")
	}
	 := [0]

	// debug
	,  := handleDebug(, )
	if  != nil {
		return 
	}

	// init fs watcher
	if  {
		,  = initWatcher(, , )
		if  != nil {
			return 
		}
	}

	// addr from a file
	if  {

		,  := os.ReadFile()
		if  != nil {
			return fmt.Errorf("%w\n", )
		}
		 = []string{strings.TrimSpace(string())}

		// watch
		if  {
			 = .Add()
			if  != nil {
				return fmt.Errorf("failed to watch file: %w", )
			}
		}

		// addrs from a dir
	} else if  {
		,  = addrsFromDir()
		if  != nil {
			return fmt.Errorf("failed to scan directory: %w", )
		}
		if len() == 0 {
			return fmt.Errorf("no .addr files found in %s", )
		}

		// watch
		if  {
			 = .Add()
			if  != nil {
				return fmt.Errorf("failed to watch dir: %w", )
			}
		}

		// addr from CLI
	} else {
		 = []string{}
	}

	// collected addresses
	.Addrs = 
	.DbgAddr = 

	// CLI mode
	if len() > 0 {

		// parse dedicated CLI flags
		,  := .Flags().GetBool("req-all")
		if  != nil {
			return 
		}

		// start and try to connect
		.Add1(ss.Start, nil)
		 = amhelp.WaitForAll(.Ctx(), time.Second,
			.When1(ss.ConnectedFully, nil))
		if errors.Is(, am.ErrTimeout) {
			if .Is1(ss.Connected) && .Not1(ss.ConnectedFully) {
				if  {
					.Print("Error: Partial connection and --req-all")

					return nil
				}
				.Print("Partial connection, executing...")

			} else if .Not1(ss.Connected) {
				.Print("Error: not connected")

				return nil
			}
		}

		// exec the CLI cmd
		.SetArgs()

		return .Execute()
	}

	// TUI mode
	for ,  := range ReplCmds() {
		.AddCommand()
	}
	 := .Add(am.S{ss.Start, ss.ReplMode}, nil)

	return amhelp.ResultToErr()
}

func addrsFromDir( string) ([]string, error) {
	var  []string

	 := filepath.WalkDir(,
		func( string,  fs.DirEntry,  error) error {
			if  != nil {
				return 
			}
			if !.IsDir() && strings.HasSuffix(, ".addr") {
				,  := os.ReadFile()
				if  != nil {
					return fmt.Errorf("%s: %w\n", , )
				}
				 = append(, strings.TrimSpace(string()))
			}

			return nil
		})

	return , 
}

func handleDebug( *cobra.Command,  *am.Machine) (string, error) {
	,  := .Flags().GetInt("log-level")
	if  != nil {
		return "", 
	}
	 = min(4, )
	 := am.LogLevel()
	,  := .Flags().GetString("am-dbg-addr")
	if  != nil {
		return "", 
	}
	if  != "" {
		 := amhelp.MachDebug(, , , false,
			amhelp.SemConfigEnv(true))
		if  != nil {
			return "", 
		}
	}

	return , nil
}

// TODO watch in a state, handle filenames other then *.addr, add/remove
//   - only affected clients, dont re-start
func initWatcher(
	 *am.Machine,  string,  bool,
) (*fsnotify.Watcher, error) {
	,  := fsnotify.NewWatcher()
	if  != nil {
		return nil, 
	}
	.OnDispose(func( string,  context.Context) {
		_ = .Close()
	})

	// watch for changes and trigger AddrChanged
	go func() {
		var  atomic.Bool

		// TODO how very (not) nice
		var  func()
		 = func() {
			.Log("watcher: restarting")
			time.Sleep(time.Second)
			var  []string
			if  {
				,  = addrsFromDir()
				if  != nil {
					.AddErr(, nil)
					return
				}
			} else {
				,  := os.ReadFile()
				if  != nil {
					.AddErr(, nil)
				}
				 = []string{string()}
			}
			.Log("watcher: collected %d addresses", len())

			.Add1(ss.AddrChanged, Pass(&A{
				Addrs: ,
			}))
			.Store(false)
		}

		for {
			select {
			case <-.Ctx().Done():
				return

			case ,  := <-.Events:
				if ! {
					return
				}

				// change
				if .Has(fsnotify.Write) || .Has(fsnotify.Create) {
					if !strings.HasSuffix(.Name, ".addr") {
						continue
					}

					if !.CompareAndSwap(false, true) {
						// already scheduled
						continue
					}

					// debounce and re-start
					go ()
				}

				// removed TODO handle better
				// if event.Op&fsnotify.Remove == fsnotify.Remove {
				// }
			}
		}
	}()

	return , nil
}

func ( *Repl) []*cobra.Command {
	 := .Mach

	// Add command
	 := &cobra.Command{
		Use: "add MACH STATES",
		Example: "$ add mach1 Foo Bar \\\n" +
			"    --arg name1 --val val1 \\\n" +
			"    --arg name2 --val val2",
		Short:   "Add states to a single machine",
		Args:    cobra.MinimumNArgs(2),
		GroupID: "mutating",
		RunE: func( *cobra.Command,  []string) error {
			if .Mach.Not1(ss.Connected) {
				return fmt.Errorf("not connected\n")
			}

			,  := mutationGetArgs()
			if  != nil {
				return 
			}

			// mutation
			 := A{
				MachId:  [0],
				States:  [1:],
				MutArgs: ,
			}
			 := .Add1(ss.CmdAdd, Pass(&))
			if  != am.Executed {
				.Print(.String())
			}

			return nil
		},
	}
	MutationFlags(, , false)

	// Remove command
	 := &cobra.Command{
		Use: "remove MACH STATES",
		Example: "$ remove mach1 Foo Bar \\\n" +
			"    --arg name1 --val val1 \\\n" +
			"    --arg name2 --val val2",
		Short:   "Removed states from a single machine",
		Args:    cobra.MinimumNArgs(2),
		GroupID: "mutating",
		RunE: func( *cobra.Command,  []string) error {
			if .Mach.Not1(ss.Connected) {
				return fmt.Errorf("not connected\n")
			}

			,  := mutationGetArgs()
			if  != nil {
				return 
			}

			// mutation
			 := A{
				MachId:  [0],
				States:  [1:],
				MutArgs: ,
			}
			 := .Add1(ss.CmdRemove, Pass(&))

			return amhelp.ResultToErr()
		},
	}
	MutationFlags(, , false)

	// TODO cmd: set

	// Group Add command
	 := &cobra.Command{
		Use: "group-add STATES",
		Example: "$ group-add -r myid-.\\* Foo Bar \\\n" +
			"    --arg name1 --val val1 \\\n" +
			"    --arg name2 --val val2",
		Short:   "Add states to a group of machines",
		Args:    cobra.MinimumNArgs(1),
		GroupID: "mutating",
		RunE: func( *cobra.Command,  []string) error {
			if .Mach.Not1(ss.Connected) {
				return fmt.Errorf("not connected\n")
			}

			,  := mutationGetArgs()
			if  != nil {
				return 
			}

			// filters
			,  := listFlagsToFilters()
			if  != nil {
				return 
			}
			.SkipDisconn = true

			// list machines and collect IDs
			,  := .ListMachines()
			if  != nil {
				.PrintErr(.Error())
				return nil
			}
			 := make([]string, len())
			for ,  := range  {
				[] = .NetMach.RemoteId()
			}

			// mutation
			 := A{
				MachIds: ,
				States:  ,
				MutArgs: ,
			}
			 := .Add1(ss.CmdGroupAdd, Pass(&))
			if  != am.Executed {
				.Print(.String())
			}

			return nil
		},
	}
	MutationFlags(, , true)

	// Group Add command
	 := &cobra.Command{
		Use: "group-remove STATES",
		Example: "$ group-remove -r myid-.\\* Foo Bar \\\n" +
			"    --arg name1 --val val1 \\\n" +
			"    --arg name2 --val val2",
		Short:   "Remove states from a group of machines",
		Args:    cobra.MinimumNArgs(1),
		GroupID: "mutating",
		RunE: func( *cobra.Command,  []string) error {
			if .Mach.Not1(ss.Connected) {
				return fmt.Errorf("not connected\n")
			}

			,  := mutationGetArgs()
			if  != nil {
				return 
			}

			// filters
			,  := listFlagsToFilters()
			if  != nil {
				return 
			}
			.SkipDisconn = true

			// list machines and collect IDs
			,  := .ListMachines()
			if  != nil {
				.PrintErr(.Error())
				return nil
			}
			 := make([]string, len())
			for ,  := range  {
				[] = .NetMach.RemoteId()
			}

			// mutation
			 := A{
				MachIds: ,
				States:  ,
				MutArgs: ,
			}
			 := .Add1(ss.CmdGroupAdd, Pass(&))
			if  != am.Executed {
				.Print(.String())
			}

			return nil
		},
	}
	MutationFlags(, , true)

	return []*cobra.Command{, , , }
}

func listFlagsToFilters( *cobra.Command) (*ListFilters, error) {
	 := &ListFilters{}

	// id-regexp
	if ,  := .Flags().GetString("id-regexp");  != nil {
		return nil, 
	} else if  != "" {
		,  := regexp.Compile()
		if  != nil {
			return nil, 
		}
		.IdRegexp = 
	}

	// id-partial
	if ,  := .Flags().GetString("id-partial");  != nil {
		return nil, 
	} else if  != "" {
		.IdSubstr = 
	}

	if ,  := .Flags().GetString("id-prefix");  != nil {
		return nil, 
	} else if  != "" {
		.IdPrefix = 
	}

	// id-suffix
	if ,  := .Flags().GetString("id-suffix");  != nil {
		return nil, 
	} else if  != "" {
		.IdSuffix = 
	}

	// parent
	if ,  := .Flags().GetString("parent");  != nil {
		return nil, 
	} else if  != "" {
		.Parent = 
	}

	// limit
	if ,  := .Flags().GetInt("limit");  != nil {
		return nil, 
	} else if  > 0 {
		.Limit = 
	}

	// from
	if ,  := .Flags().GetInt("from");  != nil {
		return nil, 
	} else if  > 0 {
		.StartIdx = 
	}

	// active
	if ,  := .Flags().GetStringArray("active");  != nil {
		return nil, 
	} else if len() > 0 {
		.StatesActive = 
	}

	// inactive
	if ,  := .Flags().GetStringArray(
		"inactive");  != nil {
		return nil, 
	} else if len() > 0 {
		.StatesInactive = 
	}

	// mtime-min
	if ,  := .Flags().GetUint64("mtime-min");  != nil {
		return nil, 
	} else if  > 0 {
		.MtimeMin = 
	}

	// mtime-max
	if ,  := .Flags().GetUint64("mtime-max");  != nil {
		return nil, 
	} else if  > 0 {
		.MtimeMax = 
	}

	// mtime-states
	if ,  := .Flags().GetStringArray(
		"mtime-states");  != nil {
		return nil, 
	} else if len() > 0 {
		.MtimeStates = 
	}

	return , nil
}

func mutationGetArgs( *cobra.Command) ([2][]string, error) {
	var  [2][]string

	// check flags
	,  := .Flags().GetStringArray("arg")
	if  != nil {
		return , 
	}
	,  := .Flags().GetStringArray("val")
	if  != nil {
		return , 
	}
	if len() != len() {
		return , fmt.Errorf(
			"the number of arguments (--arg) and values (--val) must match")
	}

	return [2][]string{, }, nil
}

type ReplApi interface {
	NetMachArgs(machId string) []string
}

func ( ReplApi,  *cobra.Command,  bool) {
	.Flags().StringArray("arg", []string{},
		"Argument name (repeatable)")
	.Flags().StringArray("val", []string{},
		"Argument value (repeatable)")

	// completion TODO groups
	_ = .RegisterFlagCompletionFunc("arg", func(
		 *cobra.Command,  []string,  string,
	) ([]string, cobra.ShellCompDirective) {
		return .NetMachArgs([0]), cobra.ShellCompDirectiveDefault
	})
	// if err != nil {
	// 	// DEBUG
	// 	panic(err)
	// }

	if  {
		ListingFlags()
		// TODO --done and --parallel "Pass a done state to control a pool of async
		//  mutations"
		// TODO --strict "Makes sure all matched machines implement passed states"
	}
}

func ( *cobra.Command) {
	.Flags().StringArrayP("active", "a", []string{},
		"Filter by an active state (repeatable)")
	.Flags().StringArrayP("inactive", "i", []string{},
		"Filter by an inactive state (repeatable)")
	.Flags().StringArrayP("mtime-states", "m", []string{},
		"Take machine time only from these states (repeatable)")
	.Flags().Uint64P("mtime-min", "t", 0,
		"Min machine time, e.g. \"1631616000\"")
	.Flags().Uint64P("mtime-max", "T", 0,
		"Max machine time, e.g. \"1631616000\"")
	.Flags().StringP("parent", "P", "", "Filter by parent ID")
	.Flags().StringP("id-regexp", "r", "", "Regexp to match machine IDs")
	.Flags().StringP("id-partial", "I", "", "Substring to match machine IDs")
	.Flags().StringP("id-prefix", "p", "", "Prefix to match machine IDs")
	.Flags().StringP("id-suffix", "s", "", "Suffix to match machine IDs")
	.Flags().IntP("limit", "l", 0, "Mutate up to N machines")
	.Flags().IntP("from", "f", 0, "Start from this index")
}

func ( *Repl) []*cobra.Command {
	 := .Mach

	// Script command
	 := &cobra.Command{
		Use:     "script FILE",
		Short:   "Execute a REPL script from a file",
		GroupID: "repl",
		Args:    cobra.ExactArgs(1),
		RunE: func( *cobra.Command,  []string) error {
			return nil
		},
	}

	// Exit command
	 := &cobra.Command{
		Use:     "exit",
		Short:   "Exit the REPL",
		GroupID: "repl",
		RunE: func( *cobra.Command,  []string) error {
			.Add1(ss.Disposing, nil)
			.Remove1(ss.ReplMode, nil)

			return nil
		},
	}

	// Cheatsheet command
	 := &cobra.Command{
		Use:     "cheatsheet",
		Short:   "Show cheatsheet",
		GroupID: "repl",
		RunE: func( *cobra.Command,  []string) error {
			.Print("Printing from cheatsheet command")

			return nil
		},
	}

	return []*cobra.Command{, , }
}

func ( *Repl) []*cobra.Command {
	 := .Mach

	// Connect command
	// TODO connet to a new mach via addr
	 := &cobra.Command{
		Use:     "connect",
		Short:   "Try to re-connect to all machines",
		GroupID: "repl",
		RunE: func( *cobra.Command,  []string) error {
			 := .Add1(ss.Connecting, nil)
			.Print(.String())

			// TODO block for some time, print info

			return amhelp.ResultToErr()
		},
	}

	return []*cobra.Command{}
}

func ( *Repl) []*cobra.Command {
	// mach := repl.Mach

	// When command
	 := &cobra.Command{
		Use:     "when MACH STATE",
		Short:   "Wait for active states of a single machine",
		Example: "when mach1 Foo",
		Args:    cobra.ExactArgs(2),
		GroupID: "waiting",
		RunE: func( *cobra.Command,  []string) error {
			if .Mach.Not1(ss.Connected) {
				return fmt.Errorf("not connected\n")
			}

			 := .NetMach([0])
			if  == nil {
				return nil
			}
			 := [1]
			<-.When1(, nil)

			 := .Tick()
			.Print("%d", )

			return nil
		},
	}

	// TODO timeout

	// When-not command
	 := &cobra.Command{
		Use:     "when-not MACH STATE",
		Short:   "Wait for inactive states of a single machine",
		Example: "when-not mach1 Foo",
		Args:    cobra.ExactArgs(2),
		GroupID: "waiting",
		RunE: func( *cobra.Command,  []string) error {
			if .Mach.Not1(ss.Connected) {
				return fmt.Errorf("not connected\n")
			}

			 := .NetMach([0])
			if  == nil {
				return nil
			}
			 := [1]
			<-.WhenNot1(, nil)

			 := .Tick()
			.Print("%d", )

			return nil
		},
	}

	// TODO timeout

	// When-time command
	 := &cobra.Command{
		Use:     "when-time MACH STATES TIMES",
		Short:   "Wait for a specific machine time of a single machine",
		Example: "when-time mach1 -s Foo -t 1000 -s Bar -t 2000",
		GroupID: "waiting",
		Args:    cobra.MinimumNArgs(1),
		RunE: func( *cobra.Command,  []string) error {
			if .Mach.Not1(ss.Connected) {
				return fmt.Errorf("not connected\n")
			}

			 := .NetMach([0])
			if  == nil {
				return nil
			}

			// Fetching the flag values
			,  := .Flags().GetStringArray("state")
			if  != nil {
				return 
			}
			,  := .Flags().GetStringArray("time")
			if  != nil {
				return 
			}

			// Check if the number of states and times are the same
			if len() != len() {
				return fmt.Errorf(
					"the number of states (-s) and times (-t) must be the same")
			}
			if len() == 0 {
				return fmt.Errorf("no states (-s) specified")
			}

			// Parse times to uint64
			 := make([]uint64, len())
			for ,  := range  {
				,  := strconv.ParseUint(, 10, 64)
				if  != nil {
					return fmt.Errorf("invalid time value '%s': %v", , )
				}
				[] = 
			}

			<-.WhenTime(, , nil)

			 := .Time()
			.Print("%v", )

			return nil
		},
	}
	.Flags().StringArrayP("time", "t", []string{},
		"Machine time (repeatable)")
	.Flags().StringArrayP("state", "s", []string{},
		"State name (repeatable)")
	// TODO timeout

	// TODO when-args

	return []*cobra.Command{, , }
}

func ( *Repl) []*cobra.Command {
	// List command
	// TODO support returning net addresses
	 := &cobra.Command{
		Use:     "list",
		Example: "list -a Foo -a Bar --mtime-min 1631",
		Short:   "List handshaked machines",
		GroupID: "repl",
		RunE: func( *cobra.Command,  []string) error {
			return listRun(, , )
		},
	}
	ListingFlags()
	.Flags().BoolP("states", "z", true, "Print states")
	.Flags().BoolP("states-all", "Z", false,
		"Print all states (requires --states)")
	.Flags().BoolP("disconn", "d", true, "Show disconnected")
	// TODO --show-inherited (true)

	// TODO update usage to:
	//  > arpc host:port list [flags]
	// templ := listCmd.UsageTemplate()
	// templ = strings.Replace(templ, " {{.CommandPath}} [command]",
	// 	" {{.CommandPath}} host:port [command]", 1)
	// listCmd.SetUsageTemplate(templ)

	// Mach command
	 := &cobra.Command{
		Use:     "mach",
		Short:   "Show states of a single machine",
		GroupID: "inspecting",
		Args:    cobra.ExactArgs(1),
		RunE: func( *cobra.Command,  []string) error {
			 := .NetMach([0])
			if  == nil {
				.PrintErr("mach ID unknown")
				return nil
			}

			 := .String()
			if .Flag("all").Changed {
				 = .StringAll()
			}
			.Print()

			return nil
		},
	}
	.Flags().Bool("all", false, "Show all states")

	// Time command
	// TODO specific states via param
	 := &cobra.Command{
		Use:     "time",
		Short:   "Show the time of a single machine",
		Example: "sum mach1 Foo Bar",
		GroupID: "inspecting",
		Args:    cobra.ExactArgs(1),
		RunE: func( *cobra.Command,  []string) error {
			 := .NetMach([0])
			if  == nil {
				.PrintErr("mach ID unknown")
				return nil
			}

			,  := .Flags().GetBool("sum")
			if  != nil {
				return 
			}

			if  {
				 := .Time(nil).Sum(nil)
				.Print("%d", )

				return nil
			}

			 := .Time(nil)
			.Print("%v", )

			return nil
		},
	}
	.Flags().Bool("sum", false, "Show the time sum")

	// Inspect command
	// TODO specific states via param
	 := &cobra.Command{
		Use:     "inspect MACH",
		Short:   "Inspect a single machine",
		GroupID: "inspecting",
		Args:    cobra.ExactArgs(1),
		RunE: func( *cobra.Command,  []string) error {
			 := .NetMach([0])
			if  == nil {
				.PrintErr("mach ID unknown")
				return nil
			}

			 := "mach://" + .RemoteId() + "\n\n"
			 += .Inspect(nil)
			.Print()

			return nil
		},
	}

	// Status command
	 := &cobra.Command{
		Use:     "status",
		Short:   "Show the connection status",
		GroupID: "repl",
		RunE: func( *cobra.Command,  []string) error {
			,  := .ListMachines(&ListFilters{NoSchema: true})
			if  != nil {
				.PrintErr(.Error())
				return nil
			}

			, ,  := 0, 0, 0
			for ,  := range  {
				if .Mach.Is1(ssrpc.ClientStates.Ready) {
					++
				} else if .Mach.Is1(ss.Connecting) {
					++
				} else {
					++
				}
			}

			// TODO get the list via a state, take total from list of registered
			//  (named) addresses
			.Print(strings.Repeat("%-15s %d\n", 4),
				"Connected:", ,
				"Connecting:", ,
				"Disconnected:", ,
				"Total:", len(),
			)

			return nil
		},
	}

	return []*cobra.Command{, , , , }
}

func listRun( *Repl,  *cobra.Command,  []string) error {
	// -> 1. C ns_id123 22d t6,7234,234 (Foo:1 Bar:1)
	// mach := repl.Mach

	,  := listFlagsToFilters()
	if  != nil {
		return 
	}

	,  := .Flags().GetBool("states-all")
	if  != nil {
		return 
	}

	,  := .Flags().GetBool("states")
	if  != nil {
		return 
	}

	,  := .Flags().GetBool("disconn")
	if  != nil {
		return 
	}
	.SkipDisconn = !

	,  := .ListMachines()
	if  != nil {
		.PrintErr(.Error())
		return nil
	}

	for ,  := range  {
		 := .NetMach

		 := ""
		if  {
			 = .String()

			if  {
				 = .StringAll()
			}
		}

		 := "C"
		if .Mach.Not1(ssrpc.ClientStates.Ready) {
			 = "D"
		}
		if .Has1(ssam.BasicStates.Ready) && .Is1(ssam.BasicStates.Ready) {
			 += "R"
		} else if .Has1(ssam.BasicStates.Start) && .Is1(ssam.BasicStates.Start) {
			 += "S"
		}

		// TODO conns since time in htime
		 := .Time(nil).Sum(nil)
		.Print("%d. %s t%d\n   %s: %s", +1, .RemoteId(), , , )
	}

	return nil
}