package pdu

import (
	"bytes"
	"log"
	"sync"
)

type BufferPoolManager struct {
	pools map[int]*sync.Pool
	mu    sync.RWMutex
	debug bool
}

func (bpm *BufferPoolManager) logf(format string, args ...interface{}) {
	if bpm.debug {
		log.Printf(format, args...)
	}
}

func NewBufferPoolManager() *BufferPoolManager {
	return &BufferPoolManager{
		pools: make(map[int]*sync.Pool),
	}
}

func (bpm *BufferPoolManager) Get(size int) *bytes.Buffer {
	bpm.mu.RLock()
	pool, exists := bpm.pools[size]
	bpm.mu.RUnlock()

	if !exists {
		bpm.mu.Lock()
		// Double-check if another goroutine added the pool while we were waiting
		pool, exists = bpm.pools[size]
		if !exists {
			bpm.logf("Creating new pool for size %d\n", size)
			pool = &sync.Pool{
				New: func() interface{} {
					bpm.logf("Creating new buffer of size %d\n", size)
					buf := bytes.NewBuffer(make([]byte, size))
					buf.Reset()
					return buf
				},
			}
			bpm.pools[size] = pool
		}
		bpm.mu.Unlock()
	}

	buf := pool.Get().(*bytes.Buffer)
	bpm.logf("Returning buffer of size %d: %p\n", buf.Cap(), buf)
	return buf
}

func (bpm *BufferPoolManager) Put(buf *bytes.Buffer) {
	size := buf.Cap()
	bpm.mu.RLock()
	pool, exists := bpm.pools[size]
	bpm.mu.RUnlock()

	if !exists {
		bpm.logf("Cannot return %p, No pool for size %d\n", buf, size)
		return
	}

	buf.Reset()
	pool.Put(buf)
	bpm.logf("Returned buffer of size %d: %p\n", size, buf)
}
