// Package barpool provides access to the global
// pool of progress bars, so they could be rendered
// altogether.
package barpool

import (
	"fmt"
	"io"
	"os"

	"github.com/cheggaaa/pb/v3"

	"github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/terminal"
)

var isDisabled bool

// Disable sets progress bar to be no-op if v==true
func Disable(v bool) {
	isDisabled = v
}

var pool = pb.NewPool()

// Bar is an interface for progress bar
type Bar interface {
	Add(value int)
	Increment()
	Start()
	Finish()
	NewProxyReader(r io.Reader) *pb.Reader
}

type progressBar struct {
	*pb.ProgressBar
}

func (pb *progressBar) Finish()       { pb.ProgressBar.Finish() }
func (pb *progressBar) Start()        { pb.ProgressBar.Start() }
func (pb *progressBar) Add(value int) { pb.ProgressBar.Add(value) }
func (pb *progressBar) Increment()    { pb.ProgressBar.Increment() }
func (pb *progressBar) NewProxyReader(r io.Reader) *pb.Reader {
	return pb.ProgressBar.NewProxyReader(r)
}

type progressBarNoOp struct{}

func (pbno *progressBarNoOp) Finish()                               {}
func (pbno *progressBarNoOp) Start()                                {}
func (pbno *progressBarNoOp) Add(int)                               {}
func (pbno *progressBarNoOp) Increment()                            {}
func (pbno *progressBarNoOp) NewProxyReader(_ io.Reader) *pb.Reader { return nil }

// Start starts the global pool
// Must be called after all progress bars were added
func Start() error {
	if isDisabled {
		return nil
	}
	return pool.Start()
}

// Stop stops the global pool
func Stop() {
	if isDisabled {
		return
	}
	_ = pool.Stop()
}

// AddWithTemplate adds bar with the given template
// to the global pool
func AddWithTemplate(format string, total int) Bar {
	if isDisabled {
		return &progressBarNoOp{}
	}
	tpl := getTemplate(format)
	bar := pb.ProgressBarTemplate(tpl).New(total)
	pool.Add(bar)
	return &progressBar{bar}
}

// NewSingleProgress returns progress bar with given template
func NewSingleProgress(format string, total int) Bar {
	if isDisabled {
		return &progressBarNoOp{}
	}
	tpl := getTemplate(format)
	return &progressBar{pb.ProgressBarTemplate(tpl).New(total)}
}

func getTemplate(format string) string {
	isTerminal := terminal.IsTerminal(int(os.Stdout.Fd()))
	if !isTerminal {
		format = fmt.Sprintf("%s\n", format)
	}
	return format
}