package optimizelab

import (
	"bytes"
	"encoding/json"
	"reflect"
	"strings"
	"sync"
)

func GrowSlice(n int) []int {
	var out []int
	for i := 0; i < n; i++ {
		out = append(out, i)
	}
	return out
}
func ReserveSlice(n int) []int {
	out := make([]int, 0, n)
	for i := 0; i < n; i++ {
		out = append(out, i)
	}
	return out
}
func Build(parts []string, reserve bool) string {
	var b strings.Builder
	if reserve {
		n := 0
		for _, p := range parts {
			n += len(p)
		}
		b.Grow(n)
	}
	for _, p := range parts {
		b.WriteString(p)
	}
	return b.String()
}

var buffers = sync.Pool{New: func() any { return new(bytes.Buffer) }}

func EncodePooled(v any) ([]byte, error) {
	b := buffers.Get().(*bytes.Buffer)
	b.Reset()
	defer func() {
		if b.Cap() <= 64<<10 {
			b.Reset()
			buffers.Put(b)
		}
	}()
	if err := json.NewEncoder(b).Encode(v); err != nil {
		return nil, err
	}
	// The caller owns this copy; the buffer is reusable after return.
	return bytes.Clone(b.Bytes()), nil
}

type Counter struct {
	mu sync.Mutex
	n  int
}

func (c *Counter) AddOneByOne(xs []int) {
	for _, x := range xs {
		c.mu.Lock()
		c.n += x
		c.mu.Unlock()
	}
}
func (c *Counter) AddBatch(xs []int) {
	sum := 0
	for _, x := range xs {
		sum += x
	}
	c.mu.Lock()
	c.n += sum
	c.mu.Unlock()
}
func (c *Counter) Value() int { c.mu.Lock(); defer c.mu.Unlock(); return c.n }

type Record struct {
	ID   int      `json:"id"`
	Tags []string `json:"tags"`
}

func DirectID(v Record) int  { return v.ID }
func ReflectID(v Record) int { return int(reflect.ValueOf(v).FieldByName("ID").Int()) }

//go:noinline
func Local(n int) int { p := &n; return *p }

//go:noinline
func Escaped(n int) *int { return &n }
