package FikoYTGorevHavuzu

import (
	"context"
	"fmt"
	"sync"
	"time"
)

type Task func() error

type TaskResult struct {
	TaskID      string
	GroupID     string
	Success     bool
	Error       error
	Progress    float64
	ElapsedTime time.Duration
}

type WorkerPool struct {
	workerCount int
	jobs        chan *Job
	results     chan TaskResult
	groups      map[string]*Group
	mu          sync.RWMutex
	wg          sync.WaitGroup
}

type Job struct {
	TaskID   string
	GroupID  string
	Task     Task
	Priority int
}

type Group struct {
	GroupID string
	Jobs    []*Job
	Status  string
}

func NewWorkerPool(workerCount int) *WorkerPool {
	return &WorkerPool{
		workerCount: workerCount,
		jobs:        make(chan *Job, 100),
		results:     make(chan TaskResult, 100),
		groups:      make(map[string]*Group),
	}
}

func (wp *WorkerPool) Start() {
	for i := 0; i < wp.workerCount; i++ {
		go wp.worker()
	}
}

func (wp *WorkerPool) worker() {
	for job := range wp.jobs {
		start := time.Now()
		err := job.Task()
		wp.results <- TaskResult{
			TaskID:      job.TaskID,
			GroupID:     job.GroupID,
			Success:     err == nil,
			Error:       err,
			ElapsedTime: time.Since(start),
		}
		wp.wg.Done()
	}
}

func (wp *WorkerPool) AddTask(groupID, taskID string, task Task, priority int) {
	wp.mu.Lock()
	defer wp.mu.Unlock()
	job := &Job{
		TaskID:   taskID,
		GroupID:  groupID,
		Task:     task,
		Priority: priority,
	}
	if _, exists := wp.groups[groupID]; !exists {
		wp.groups[groupID] = &Group{GroupID: groupID, Status: "pending"}
	}
	wp.groups[groupID].Jobs = append(wp.groups[groupID].Jobs, job)
	wp.wg.Add(1)
	wp.jobs <- job
}

func (wp *WorkerPool) Wait() {
	wp.wg.Wait()
	close(wp.results)
}

func (wp *WorkerPool) Monitor(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			return
		case result := <-wp.results:
			fmt.Printf("Task %s in Group %s completed with success: %v, error: %v, elapsed time: %v\n", result.TaskID, result.GroupID, result.Success, result.Error, result.ElapsedTime)
		}
	}
}

func (wp *WorkerPool) CancelGroup(groupID string) {
	wp.mu.Lock()
	defer wp.mu.Unlock()
	if group, exists := wp.groups[groupID]; exists {
		group.Status = "cancelled"
		// Additional logic for cancellation can be implemented here.
	}
}

func (wp *WorkerPool) GroupProgress(groupID string) float64 {
	wp.mu.RLock()
	defer wp.mu.RUnlock()
	if group, exists := wp.groups[groupID]; exists {
		completed := 0
		for _, _ /*job*/ := range group.Jobs {
			// Assuming jobs have a Progress value for demonstration.
			completed++ // Here you can calculate based on real job progress.
		}
		return float64(completed) / float64(len(group.Jobs)) * 100
	}
	return 0
}

// Example usage
func Example() {
	wp := NewWorkerPool(4)
	wp.Start()

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	go wp.Monitor(ctx)

	task := func() error {
		time.Sleep(1 * time.Second)
		return nil
	}

	wp.AddTask("group1", "task1", task, 1)
	wp.AddTask("group1", "task2", task, 2)
	wp.AddTask("group2", "task3", task, 1)

	wp.Wait()

	progress := wp.GroupProgress("group1")
	fmt.Printf("Group1 progress: %.2f%%\n", progress)
}
