package types

import (
	
	
	
	
	
	
	
	
	
	
	
	

	am 
	
)

// Params are CLI params for am-dbg, also used as internal state via Debugger.Params.
//
//nolint:lll
type Params struct {

	// line args

	MachUrl string `arg:"positional" help:"Machine URL to connect to"`

	// main params

	ListenAddr     string   `arg:"-l,--listen-addr" default:"localhost:6831" help:"Host and port for the debugger to listen on"`
	OutputDir      string   `arg:"-d,--dir" default:"." help:"Output directory for generated files"`
	CleanOnConnect bool     `arg:"--clean-on-connect" default:"true" help:"Clean up disconnected clients on the 1st connection"`
	ImportData     string   `arg:"-i,--import-data" help:"Import an exported gob.br file"`
	FwdData        []string `arg:"-f,--fwd-data,separate" help:"Forward incoming data to other instances (repeatable)"`

	// select

	SelectConnected bool   `arg:"-c,--select-connected" help:"Select the newly connected machine, if no other is connected"`
	SelectGroup     string `arg:"--select-group" help:"Default group to select"`

	// minor params

	EnableClipboard      bool        `arg:"--enable-clipboard" default:"true" help:"Enable clipboard support"`
	EnableMouse          bool        `arg:"--enable-mouse" default:"true" help:"Enable mouse support"`
	FilterAutoTx         bool        `arg:"--filter-auto" help:"Filter automatic transitions"`
	FilterAutoCanceledTx bool        `arg:"--filter-auto-canceled" help:"Filter automatic canceled transitions"`
	FilterCanceledTx     bool        `arg:"--filter-canceled" help:"Filter canceled transitions"`
	FilterChecks         bool        `arg:"--filter-checks" help:"Filter check (read-only) transitions"`
	FilterDisconn        bool        `arg:"--filter-disconn" help:"Filter disconnected clients"`
	FilterEmptyTx        bool        `arg:"--filter-empty" help:"Filter empty transitions"`
	FilterGroup          bool        `arg:"--filter-group" default:"true" help:"Filter transitions by a selected group"`
	FilterHealthTx       bool        `arg:"--filter-health" help:"Filter health-check transitions"`
	FilterLogLevel       am.LogLevel `arg:"--filter-log-level" default:"2" help:"Filter transitions up to this log level, 0-5 (silent-everything)"`
	FilterQueuedTx       bool        `arg:"--filter-queued" help:"Filter queued transitions"`

	OutputClients  bool `arg:"--output-clients" help:"Write a detailed client list into am-dbg-clients.txt inside --dir"`
	OutputDiagrams int  `arg:"--output-diagrams" help:"Level of details for machine graph diagrams (svg, d2, mermaid) in --dir (0 off, 1-3 on) (EXPERIMENTAL)"`
	OutputLog      bool `arg:"--output-log" help:"Write the current log buffer to log.txt inside --dir"`
	OutputTx       bool `arg:"--output-tx" default:"true" help:"Write the current transition with steps into tx.md / d2 / mermaid / txt inside --dir (EXPERIMENTAL)"`

	// ui

	UiSsh bool `arg:"--ui-ssh" help:"Enable SSH headless mode on port --listen-addr +2 (EXPERIMENTAL)"`
	UiWeb bool `arg:"--ui-web" default:"true" help:"Start a web server for --dir and diagrams on --listen-addr +1 (EXPERIMENTAL)"`

	// view

	PrintVersion  bool   `arg:"--version" help:"Print version and exit"`
	StartupView   string `arg:"-v,--view" default:"tree-log" help:"Initial view (tree-log, tree-matrix, matrix)"`
	ViewNarrow    bool   `arg:"--view-narrow" help:"Force a narrow view, independently of the viewport size"`
	ViewRain      bool   `arg:"--view-rain" help:"Show the rain view"`
	ViewReader    bool   `arg:"-r,--view-reader" help:"Show the log reader view"`
	TailMode      bool   `arg:"--view-tail" default:"true" help:"Start from the latest tx"`
	ViewTimelines int    `arg:"--view-timelines" default:"2" help:"Number of timelines to show (0-2)"`

	// optimization

	LogOpsTtl time.Duration `arg:"--log-ops-ttl" default:"24h" help:"Max time to live for logs level LogOps"`
	MaxMemMb  int           `arg:"--max-mem" default:"1000" help:"Max memory usage (in MB) to flush old transitions"`

	// self-dbg

	DebugAddr    string `arg:"--dbg-am-dbg-addr" help:"Debug this instance of am-dbg with another one"`
	RaceDetector bool   `arg:"--dbg-go-race" help:"Go race detector is enabled"`
	// Id is the ID of this asyncmachine (for debugging).
	Id string `arg:"--dbg-id" default:"am-dbg" help:"ID of this instance"`
	// LogLevel is the log level of this instance (for debugging).
	LogLevel am.LogLevel `arg:"--dbg-log-level" default:"0" help:"Log level produced by this instance, 0-5 (silent-everything)"`
	DbgOtel  bool        `arg:"--dbg-otel" help:"Enable OpenTelemetry tracing for this instance"`
	ProfSrv  string      `arg:"--dbg-prof-srv" help:"Start pprof server"`

	// internal params

	// AddrHttp is the computed HTTP server address (ListenAddr port+1).
	AddrHttp string `arg:"-"`
	// AddrRpc is the RPC listen address (same as ListenAddr).
	AddrRpc string `arg:"-"`
	// AddrSsh is the computed SSH server address (ListenAddr port+2).
	AddrSsh string `arg:"-"`
	// DbgLogger is the file logger for this instance.
	DbgLogger *log.Logger `arg:"-"`
	// Filters is the active set of transition filters.
	Filters *Filters `arg:"-"`
	// Print is the output function for status messages
	Print   func(txt string, args ...any) `arg:"-"`
	ProfCpu bool                          `arg:"-"`
	ProfMem bool                          `arg:"-"`
	// Screen is an optional tcell screen override (tests, SSH).
	Screen tcell.Screen `arg:"-"`
	// Version is the computed build version string.
	Version string `arg:"-"`
}

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

// ///// FILTERS

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

// Filters controls which transitions and log entries are shown.
type Filters struct {
	SkipCanceledTx     bool
	SkipAutoTx         bool
	SkipAutoCanceledTx bool
	SkipEmptyTx        bool
	SkipHealthTx       bool
	SkipQueuedTx       bool
	SkipOutGroup       bool
	SkipChecks         bool
	LogLevel           am.LogLevel
}

func ( *Filters) ( *Filters) bool {
	if  == nil {
		return false
	}

	return .SkipCanceledTx == .SkipCanceledTx &&
		.SkipAutoTx == .SkipAutoTx &&
		.SkipAutoCanceledTx == .SkipAutoCanceledTx &&
		.SkipEmptyTx == .SkipEmptyTx &&
		.SkipHealthTx == .SkipHealthTx &&
		.SkipQueuedTx == .SkipQueuedTx &&
		.SkipOutGroup == .SkipOutGroup &&
		.SkipChecks == .SkipChecks &&
		.LogLevel == .LogLevel
}

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

// ///// PROFILING

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

// GetLogger returns a file logger, according to params.
func ( *Params,  string) *log.Logger {
	// TODO slog

	if .LogLevel <= 0 {
		return log.Default()
	}
	 := filepath.Join(, "am-dbg.log")

	// file logging
	_ = os.Remove()
	,  := os.OpenFile(, os.O_CREATE|os.O_WRONLY, 0o666)
	if  != nil {
		panic()
	}

	return log.New(, "", log.LstdFlags)
}

func ( *log.Logger,  *Params) {
	if !.ProfMem {
		return
	}

	,  := os.Create("mem.prof")
	if  != nil {
		.Fatal("could not create memory profile: ", )
	}
	defer .Close() // error handling omitted for example

	runtime.GC() // get up-to-date statistics
	if  := pprof.WriteHeapProfile();  != nil {
		.Fatal("could not write memory profile: ", )
	}
}

func ( *log.Logger,  *Params) func() {
	if !.ProfCpu {
		return nil
	}

	,  := os.Create("cpu.prof")
	if  != nil {
		.Fatal("could not create CPU profile: ", )
	}
	if  := pprof.StartCPUProfile();  != nil {
		.Fatal("could not start CPU profile: ", )
	}

	return func() {
		pprof.StopCPUProfile()
		.Close()
	}
}

func ( context.Context,  *log.Logger,  *Params) {
	if .ProfSrv == "" {
		return
	}
	go func() {
		.Println("Starting pprof server on " + .ProfSrv)
		// TODO support ctx cancel
		if  := http.ListenAndServe(.ProfSrv, nil);  != nil {
			.Fatalf("could not start pprof server: %v", )
		}
	}()
}

type MachAddress struct {
	MachId    string
	TxId      string
	MachTime  uint64
	HumanTime time.Time
	// TODO support step
	Step int
	// TODO support queue ticks
	QueueTick uint64
}

type MachTime struct {
	Id   string
	Time uint64
}

func ( *MachAddress) () *MachAddress {
	return &MachAddress{
		MachId:   .MachId,
		TxId:     .TxId,
		Step:     .Step,
		MachTime: .MachTime,
	}
}

func ( *MachAddress) () string {
	if .TxId != "" {
		 := fmt.Sprintf("mach://%s/%s", .MachId, .TxId)
		if .Step != 0 {
			 += fmt.Sprintf("/%d", .Step)
		}
		if .MachTime != 0 {
			 += fmt.Sprintf("/t%d", .MachTime)
		}

		return 
	}
	if .MachTime != 0 {
		return fmt.Sprintf("mach://%s/t%d", .MachId, .MachTime)
	}
	if !.HumanTime.IsZero() {
		return fmt.Sprintf("mach://%s/%s", .MachId, .HumanTime)
	}

	return fmt.Sprintf("mach://%s", .MachId)
}

func ( string) (*MachAddress, error) {
	// TODO merge parsing with addr bar

	,  := url.Parse()
	if  != nil {
		return nil, 
	} else if .Host == "" {
		return nil, fmt.Errorf("host missing in: %s", )
	}

	 := &MachAddress{
		MachId: .Host,
	}
	 := strings.Split(.Path, "/")
	if len() > 1 {
		.TxId = [1]
	}
	if len() > 2 {
		if ,  := strconv.Atoi([2]);  == nil {
			.Step = 
		}
	}

	return , nil
}

type MsgTxParsed struct {
	StatesAdded   []int
	StatesRemoved []int
	StatesTouched []int
	// TimeSum is machine time after this transition.
	TimeSum       uint64
	TimeDiff      uint64
	ReaderEntries []*LogReaderEntryPtr
	// Transitions which reported this one as their source
	Forks       []MachAddress
	ForksLabels []string
	// QueueTick when this tx should be executed
	ResultTick uint64
}

type MsgSchemaParsed struct {
	Groups      map[string]am.S
	GroupsOrder []string
}

type LogReaderEntry struct {
	Kind LogReaderKind
	// states are empty for logReaderWhenQueue
	States []int
	// CreatedAt is machine time when this entry was created
	CreatedAt uint64
	// ClosedAt is human time when this entry was closed, so it can be disposed.
	ClosedAt time.Time

	// per-type fields

	// Pipe is for logReaderPipeIn, logReaderPipeOut
	Pipe am.MutationType
	// Mach is for logReaderPipeIn, logReaderPipeOut, logReaderMention
	Mach string
	// Ticks is for logReaderWhenTime only
	Ticks am.Time
	// Args is for logReaderWhenArgs only
	Args string
	// QueueTick is for logReaderWhenQueue only
	QueueTick int
}

type LogReaderEntryPtr struct {
	TxId     string
	EntryIdx int
}

type LogReaderKind int

const (
	LogReaderCtx LogReaderKind = iota + 1
	LogReaderWhen
	LogReaderWhenNot
	LogReaderWhenTime
	LogReaderWhenArgs
	LogReaderWhenQueue
	LogReaderPipeIn
	LogReaderPipeOut
	// TODO mentions of machine IDs
	// logReaderMention
)