package main

import (
	"fmt"
	"sync"
	"time"
)

func sumUsingParallelWorker(start int64, end int64) int64 {
	var partialSum int64 = 0

	for i := start; i <= end; i++ {
		partialSum += i
	}

	return partialSum
}

func main() {
	var n int64 = 100000000
	var workerCountForSum = 4

	var tempSum int64 = 0
	fmt.Println("Calculating sum from 1 to", n, "using single loop")
	var startTime = time.Now()
	for i := int64(1); i <= n; i++ {
		tempSum += i
	}
	var duration = time.Since(startTime)
	fmt.Println("Sum using single loop =", tempSum)
	fmt.Println("Time taken for sum using single loop = ", duration)

	var wg sync.WaitGroup
	fmt.Println("\nCalculating sum from 1 to", n, "using", workerCountForSum, "parallel workers")
	chunkSize := n / int64(workerCountForSum)
	results := make([]int64, workerCountForSum)
	startTime = time.Now()
	wg.Add(workerCountForSum)
	go func() {
		defer wg.Done()
		results[0] = sumUsingParallelWorker(1, chunkSize)
	}()

	go func() {
		defer wg.Done()
		results[1] = sumUsingParallelWorker(chunkSize+1, chunkSize*2)
	}()
	go func() {
		defer wg.Done()
		results[2] = sumUsingParallelWorker(chunkSize*2+1, chunkSize*3)
	}()
	go func() {
		defer wg.Done()
		results[3] = sumUsingParallelWorker(chunkSize*3+1, n)
	}()
	wg.Wait()

	var parallelSum int64 = 0

	for _, value := range results {
		parallelSum += value
	}

	duration = time.Since(startTime)

	fmt.Println("Sum using parallel workers =", parallelSum)
	fmt.Println("Time taken for sum using parallel workers =", duration)

	fmt.Println("All workers finished")
}
