package main

import (
	"context"
	"errors"
	"fmt"
	"strings"
	"sync"
	"time"

	"os/exec"

	"git.jingrow.com/cilium/ebpf/perf"
)

// CircularBuffer to keep fixed-size samples

type CircularBuffer[T any] struct {
	mu   sync.RWMutex
	data []T
	head int
	full bool
	size int
}

func NewCircularBuffer[T any](size int) *CircularBuffer[T] {
	return &CircularBuffer[T]{
		data: make([]T, size),
		size: size,
	}
}

func (c *CircularBuffer[T]) Add(s T) {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.data[c.head] = s
	c.head = (c.head + 1) % c.size
	if c.head == 0 {
		c.full = true
	}
}

func (c *CircularBuffer[T]) GetLatest() *T {
	c.mu.RLock()
	defer c.mu.RUnlock()

	if len(c.data) == 0 {
		return nil
	}

	// Get most recent item (just before head)
	idx := c.head - 1
	if idx < 0 {
		idx = len(c.data) - 1
	}
	return &c.data[idx]
}

func (c *CircularBuffer[T]) Snapshot() []T {
	c.mu.RLock()
	defer c.mu.RUnlock()
	if !c.full && c.head == 0 {
		return nil
	}
	var out []T
	if c.full {
		out = append(out, c.data[c.head:]...)
		out = append(out, c.data[:c.head]...)
	} else {
		out = append(out, c.data[:c.head]...)
	}
	return out
}

// Helper methods

func isPerfClosedError(err error) bool {
	if err == nil {
		return false
	}
	if err == perf.ErrClosed {
		return true
	}
	e := strings.ToLower(err.Error())
	if (strings.Contains(e, "perf reader closed") ||
		strings.Contains(e, "reader is closed") ||
		strings.Contains(e, "closed") && strings.Contains(e, "perf")) ||
		strings.Contains(strings.ToLower(err.Error()), "file already closed") {
		return true
	}
	return false
}

// func cStr(b []byte) string {
// 	if i := bytes.IndexByte(b, 0); i >= 0 {
// 		return string(b[:i])
// 	}
// 	return string(b)
// }

func captureMariaDBProcessList() (string, error) {
	// max 10s timeout
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	cmd := exec.CommandContext(ctx, "mariadb", "-e", "SHOW FULL PROCESSLIST\\G")
	output, err := cmd.CombinedOutput()
	if ctx.Err() == context.DeadlineExceeded {
		return "", errors.New("mariadb process list command timed out")
	}

	if err != nil {
		return "", fmt.Errorf("error executing mariadb command: %v, output: %s", err, string(output))
	}

	return string(output), nil
}
