package main

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

// section: fixed-mutex
// CounterMutex uses a mutex to prevent race conditions
type CounterMutex struct {
	mu    sync.Mutex
	count int
}

// Increment is now safe for concurrent use
func (c *CounterMutex) Increment() {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.count++
}

// Value is now safe for concurrent use
func (c *CounterMutex) Value() int {
	c.mu.Lock()
	defer c.mu.Unlock()
	return c.count
}

// section: fixed-mutex

// section: fixed-atomic
// CounterAtomic uses atomic operations for better performance
type CounterAtomic struct {
	count int64
}

// Increment uses atomic operation - no mutex needed
func (c *CounterAtomic) Increment() {
	atomic.AddInt64(&c.count, 1)
}

// Value uses atomic load
func (c *CounterAtomic) Value() int64 {
	return atomic.LoadInt64(&c.count)
}

// section: fixed-atomic

// section: main
func main() {
	fmt.Println("=== Counter with Mutex ===")
	runMutexTest()

	fmt.Println("\n=== Counter with Atomic Operations ===")
	runAtomicTest()
}

func runMutexTest() {
	counter := &CounterMutex{}
	var wg sync.WaitGroup

	for i := 0; i < 1000; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for j := 0; j < 100; j++ {
				counter.Increment()
			}
		}()
	}

	wg.Wait()
	fmt.Printf("Expected: 100000\n")
	fmt.Printf("Actual:   %d\n", counter.Value())
	fmt.Println("✓ No race condition!")
}

func runAtomicTest() {
	counter := &CounterAtomic{}
	var wg sync.WaitGroup

	for i := 0; i < 1000; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for j := 0; j < 100; j++ {
				counter.Increment()
			}
		}()
	}

	wg.Wait()
	fmt.Printf("Expected: 100000\n")
	fmt.Printf("Actual:   %d\n", counter.Value())
	fmt.Println("✓ No race condition! (Atomic is faster than mutex for simple counters)")
}

// section: main

// section: output
// Output:
// === Counter with Mutex ===
// Expected: 100000
// Actual:   100000
// ✓ No race condition!
//
// === Counter with Atomic Operations ===
// Expected: 100000
// Actual:   100000
// ✓ No race condition! (Atomic is faster than mutex for simple counters)
// section: output
