/*
·━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━·
:                                                                               :
:   █▀ █ █▀▀   ·   Blazing-fast pentesting suite                                :
:   ▄█ █ █▀    ·   BSD 3-Clause License                                         :
:                                                                               :
:   (c) 2022-2025 vmfunc (vmfunc), xyzeva,                        :
:                 lunchcat alumni & contributors                                :
:                                                                               :
·━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━·
*/

package output

import (
	"fmt"
	"sync"
	"sync/atomic"
)

// Progress bar configuration
const (
	progressWidth   = 30
	progressFilled  = "="
	progressCurrent = ">"
	progressEmpty   = " "
)

// Progress displays a progress bar for operations with known counts
type Progress struct {
	total    int64
	current  int64
	message  string
	lastItem string
	mu       sync.Mutex
	paused   bool
}

// NewProgress creates a new progress bar
func NewProgress(total int, message string) *Progress {
	return &Progress{
		total:   int64(total),
		message: message,
	}
}

// Increment advances the progress by 1 and optionally updates the current item
func (p *Progress) Increment(item string) {
	atomic.AddInt64(&p.current, 1)

	p.mu.Lock()
	p.lastItem = item
	paused := p.paused
	p.mu.Unlock()

	if !paused {
		p.render()
	}
}

// Set sets the progress to a specific value
func (p *Progress) Set(current int, item string) {
	atomic.StoreInt64(&p.current, int64(current))

	p.mu.Lock()
	p.lastItem = item
	paused := p.paused
	p.mu.Unlock()

	if !paused {
		p.render()
	}
}

// Pause temporarily stops rendering (use before printing other output)
func (p *Progress) Pause() {
	p.mu.Lock()
	p.paused = true
	p.mu.Unlock()
	ClearLine()
}

// Resume resumes rendering after a pause
func (p *Progress) Resume() {
	p.mu.Lock()
	p.paused = false
	p.mu.Unlock()
	p.render()
}

// Done clears the progress bar line
func (p *Progress) Done() {
	if apiMode || !IsTTY {
		return
	}
	ClearLine()
}

func (p *Progress) render() {
	if apiMode {
		return
	}

	// In non-TTY mode, print progress at milestones only
	if !IsTTY {
		current := atomic.LoadInt64(&p.current)
		total := p.total
		percent := int(current * 100 / total)

		// Print at 0%, 25%, 50%, 75%, 100%
		if current == 1 || percent == 25 || percent == 50 || percent == 75 || current == total {
			fmt.Printf("    [%d%%] %d/%d\n", percent, current, total)
		}
		return
	}

	current := atomic.LoadInt64(&p.current)
	total := p.total

	p.mu.Lock()
	lastItem := p.lastItem
	p.mu.Unlock()

	// Calculate percentage
	percent := 0
	if total > 0 {
		percent = int(current * 100 / total)
	}

	// Build progress bar
	filled := 0
	if total > 0 {
		filled = int(progressWidth * current / total)
	}
	if filled > progressWidth {
		filled = progressWidth
	}

	bar := ""
	for i := 0; i < progressWidth; i++ {
		if i < filled {
			bar += progressFilled
		} else if i == filled && current < total {
			bar += progressCurrent
		} else {
			bar += progressEmpty
		}
	}

	// Truncate item if too long
	maxItemLen := 30
	if len(lastItem) > maxItemLen {
		lastItem = lastItem[:maxItemLen-3] + "..."
	}

	// Format: [========>          ] 45% (4500/10000) /admin
	line := fmt.Sprintf("    [%s] %3d%% (%d/%d) %s",
		prefixInfo.Render(bar),
		percent,
		current,
		total,
		Muted.Render(lastItem),
	)

	ClearLine()
	fmt.Print(line)
}
