package debugger

import (
	
	
	
	
	
	
	

	
	
	
	

	
	

	am 
)

const (
	// TODO light mode
	colorActive     = tcell.ColorOlive
	colorActive2    = tcell.ColorGreenYellow
	colorInactive   = tcell.ColorLimeGreen
	colorHighlight  = tcell.ColorDarkSlateGray
	colorHighlight2 = tcell.ColorDimGray
	colorHighlight3 = tcell.Color233
	colorErr        = tcell.ColorRed
	// TODO customize
	playInterval = 500 * time.Millisecond
	// TODO add param --max-clients
	maxClients            = 5000
	timeFormat            = "15:04:05.000000000"
	fastJumpAmount        = 50
	arrowThrottleMs       = 200
	logUpdateDebounce     = 300 * time.Millisecond
	sidebarUpdateDebounce = time.Second
	searchAsTypeWindow    = 1500 * time.Millisecond
	heartbeatInterval     = 1 * time.Minute
	// heartbeatInterval = 5 * time.Second
	// msgMaxAge             = 0

	// maxMemMb = 100
	maxMemMb        = 50
	msgMaxThreshold = 300
	// max txs queued for scrolling the timelines
	scrollTxThrottle = 3
)

var colorDefault = cview.Styles.PrimaryTextColor

const (
	// row 1
	toolFilterCanceledTx ToolName = "skip-canceled"
	toolFilterQueuedTx   ToolName = "skip-queued"
	toolFilterAutoTx     ToolName = "skip-auto"
	toolFilterEmptyTx    ToolName = "skip-empty"
	toolFilterHealth     ToolName = "skip-health"
	toolFilterOutGroup   ToolName = "skip-outgroup"
	toolFilterChecks     ToolName = "skip-checks"
	toolFilterDisconn    ToolName = "skip-disconn"
	ToolLogTimestamps    ToolName = "hide-timestamps"
	ToolFilterTraces     ToolName = "hide-traces"
	toolLog              ToolName = "log"
	toolDiagrams         ToolName = "diagrams"
	toolTimelines        ToolName = "timelines"
	// toolLog0              ToolName = "log-0"
	// toolLog1              ToolName = "log-1"
	// toolLog2              ToolName = "log-2"
	// toolLog3              ToolName = "log-3"
	// toolLog4              ToolName = "log-4"
	toolReader ToolName = "reader"
	toolRain   ToolName = "rain"
	toolWeb    ToolName = "web"

	// row 2

	toolHelp     ToolName = "help"
	toolPlay     ToolName = "play"
	toolTail     ToolName = "tail"
	toolPrev     ToolName = "prev"
	toolNext     ToolName = "next"
	toolJumpNext ToolName = "jump-next"
	toolJumpPrev ToolName = "jump-prev"
	toolFirst    ToolName = "first"
	toolLast     ToolName = "last"
	toolExpand   ToolName = "expand"
	toolMatrix   ToolName = "matrix"
	toolExport   ToolName = "export"
	toolNextStep ToolName = "next-step"
	toolPrevStep ToolName = "prev-step"
)

type ToolName string

type Client struct {
	*server.Client

	CursorTx1       int
	ReaderCollapsed bool
	CursorStep1     int
	SelectedState   string
	// extracted log entries per tx ID
	// TODO GC when all entries are closedAt and the first client's tx is later
	//  than the latest closedAt; whole tx needs to be disposed at the same time
	LogReader map[string][]*types.LogReaderEntry

	logRenderedCursor1    int
	logRenderedLevel      am.LogLevel
	logRenderedFilters    *types.Filters
	logRenderedTimestamps bool
	logReaderMx           sync.Mutex
}

func init() {
	gob.Register(server.Exportable{})
	gob.Register(am.Relation(0))
}

func newClient(, ,  string,  *server.Exportable) *Client {
	 := &Client{
		Client: &server.Client{
			Id:         ,
			ConnId:     ,
			SchemaHash: ,
			Exportable: ,
		},
		LogReader: make(map[string][]*types.LogReaderEntry),
	}
	.ParseSchema()

	return 
}

func ( *Client) ( string,  *types.LogReaderEntry) int {
	.logReaderMx.Lock()
	defer .logReaderMx.Unlock()

	.LogReader[] = append(.LogReader[], )

	return len(.LogReader[]) - 1
}

func ( *Client) ( string,  int) *types.LogReaderEntry {
	.logReaderMx.Lock()
	defer .logReaderMx.Unlock()

	,  := .LogReader[]
	if ! ||  >= len() {
		return nil
	}

	return []
}

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

// ///// SSH

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

func ( ssh.Session) (tcell.Screen, error) {
	, ,  := .Pty()
	if ! {
		return nil, errors.New("no pty requested")
	}
	,  := terminfo.LookupTerminfo(.Term)
	if  != nil {
		return nil, 
	}
	,  := tcell.NewTerminfoScreenFromTtyTerminfo(&tty{
		Session: ,
		size:    .Window,
		ch:      ,
	}, )
	if  != nil {
		return nil, 
	}
	return , nil
}

type tty struct {
	ssh.Session
	size     ssh.Window
	ch       <-chan ssh.Window
	resizecb func()
	mu       sync.Mutex
}

func ( *tty) () error {
	go func() {
		for  := range .ch {
			.mu.Lock()
			.size = 
			.notifyResize()
			.mu.Unlock()
		}
	}()
	return nil
}

func ( *tty) () error {
	return nil
}

func ( *tty) () error {
	return nil
}

func ( *tty) () ( tcell.WindowSize,  error) {
	.mu.Lock()
	defer .mu.Unlock()

	return tcell.WindowSize{
		Width:  .size.Width,
		Height: .size.Height,
	}, nil
}

func ( *tty) ( func()) {
	.mu.Lock()
	defer .mu.Unlock()

	.resizecb = 
}

func ( *tty) () {
	if .resizecb != nil {
		.resizecb()
	}
}

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

// ///// MISC

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

// openURL opens the specified URL in the default browser of the user.
// https://gist.github.com/sevkin/9798d67b2cb9d07cb05f89f14ba682f8
func openURL( string) error {
	var  string
	var  []string

	switch runtime.GOOS {
	case "windows":
		 = "cmd.exe"
		 = []string{
			"/c", "rundll32", "url.dll,FileProtocolHandler",
			strings.ReplaceAll(, "&", "^&"),
		}
	case "darwin":
		 = "open"
		 = []string{}
	default:
		if isWSL() {
			 = "cmd.exe"
			 = []string{"start", }
		} else {
			 = "xdg-open"
			 = []string{}
		}
	}

	 := exec.Command(, ...)
	 := .Start()
	if  != nil {
		return 
	}
	 = .Wait()
	if  != nil {
		return 
	}

	return nil
}

// isWSL checks if the Go program is running inside Windows Subsystem for Linux
func isWSL() bool {
	,  := exec.Command("uname", "-r").Output()
	if  != nil {
		return false
	}
	return strings.Contains(strings.ToLower(string()), "microsoft")
}