package main

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

// section: singleton
// Database represents a database connection
type Database struct {
	connections int
	connString  string
}

// Connect simulates establishing a database connection
func (db *Database) Connect() {
	fmt.Println("Establishing database connection...")
	time.Sleep(100 * time.Millisecond) // Simulate connection time
	db.connString = "postgres://localhost:5432/mydb"
	db.connections++
	fmt.Println("Database connected!")
}

var (
	dbInstance *Database
	once       sync.Once
)

// GetDatabase returns the singleton database instance
// The connection is initialized exactly once, even with concurrent access
func GetDatabase() *Database {
	once.Do(func() {
		fmt.Println("Creating database singleton...")
		dbInstance = &Database{}
		dbInstance.Connect()
	})
	return dbInstance
}

// section: singleton

// section: main
func main() {
	var wg sync.WaitGroup

	// Launch multiple goroutines that all need the database
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func(id int) {
			defer wg.Done()
			db := GetDatabase()
			fmt.Printf("Goroutine %d: Using database with %d connections\n",
				id, db.connections)
		}(i)
	}

	wg.Wait()

	// Verify singleton behavior
	db := GetDatabase()
	fmt.Printf("\nFinal check - Total connections: %d (should be 1)\n",
		db.connections)
}

// section: main

// section: output
// Output:
// Creating database singleton...
// Establishing database connection...
// Database connected!
// Goroutine 0: Using database with 1 connections
// Goroutine 9: Using database with 1 connections
// Goroutine 1: Using database with 1 connections
// Goroutine 2: Using database with 1 connections
// Goroutine 3: Using database with 1 connections
// Goroutine 4: Using database with 1 connections
// Goroutine 5: Using database with 1 connections
// Goroutine 6: Using database with 1 connections
// Goroutine 7: Using database with 1 connections
// Goroutine 8: Using database with 1 connections
//
// Final check - Total connections: 1 (should be 1)
// section: output
