package main

import (
	"fmt"
	"maps"
	"slices"
	"strconv"
	"unicode/utf8"
)

type UserID int64
type IDAlias = int64

func basics() {
	var id UserID = 42
	var alias IDAlias = 42
	n := 257
	fmt.Printf("%T %T\n", id, alias)
	fmt.Println(uint8(n))
	var enabled bool
	var title string
	var ptr *int
	fmt.Printf("%t %q %t\n", enabled, title, ptr == nil)
}

func changeArray(a [3]int) { a[0] = 9 }
func changeSlice(s []int) {
	s[0] = 9
	s = s[:1]
	fmt.Println("inside:", s)
}
func copying() {
	a := [3]int{1, 2, 3}
	changeArray(a)
	fmt.Println("array:", a)
	s := []int{1, 2, 3}
	changeSlice(s)
	fmt.Println("outside:", s)
}

func lengthAndCapacity() {
	s := make([]int, 2, 4)
	fmt.Println(s, len(s), cap(s))
	s = s[:4]
	s[2] = 7
	t := s[1:3]
	fmt.Println(t, len(t), cap(t))
	var a []int
	b := []int{}
	fmt.Println(a == nil, b == nil, len(a), len(b))
	a = append(a, 5)
	fmt.Println(a)
}

func sharing() {
	base := []int{10, 20, 30, 40}
	left := base[:2]
	result := append(left, 99)
	fmt.Println("base:", base)
	fmt.Println("left:", left, "result:", result)

	fenced := base[:2:2]
	fenced[0] = 11
	detached := append(fenced, 77)
	detached[0] = 88
	fmt.Println("base:", base)
	fmt.Println("fenced:", fenced, "detached:", detached)

	cloned := slices.Clone(base)
	cloned[0] = -1
	fmt.Println("base:", base, "clone:", cloned)
	nested := [][]int{{1, 2}}
	shallow := slices.Clone(nested)
	shallow[0][0] = 9
	fmt.Println("nested:", nested)
}

func growth() {
	ints := make([]int, 512)
	bytes := make([]byte, 512)
	ints = append(ints, 1)
	bytes = append(bytes, 1)
	fmt.Println("int:", len(ints), cap(ints))
	fmt.Println("byte:", len(bytes), cap(bytes))
}

func mapBasics() {
	var missing map[string]int
	v, ok := missing["x"]
	fmt.Println(len(missing), v, ok)
	delete(missing, "x")

	m := map[string]int{"b": 2, "a": 0}
	v, ok = m["a"]
	fmt.Println(v, ok)
	alias := m
	alias["a"] = 7
	for _, k := range slices.Sorted(maps.Keys(m)) {
		fmt.Println(k, m[k])
	}
	copyMap := maps.Clone(m)
	copyMap["a"] = 8
	fmt.Println(m["a"], copyMap["a"])
	clear(copyMap)
	fmt.Println(len(m), len(copyMap))
}

type Counter struct{ N int }

func mapValues() {
	m := map[string]Counter{"a": {N: 1}}
	c := m["a"]
	c.N++
	m["a"] = c
	fmt.Println(m["a"].N)
	p := map[string]*Counter{"a": {N: 1}}
	p["a"].N++
	fmt.Println(p["a"].N)
}

func textUnits() {
	s := "A中🙂"
	fmt.Println(len(s), utf8.RuneCountInString(s))
	fmt.Printf("% x\n", []byte(s))
	for i, r := range s {
		fmt.Printf("%d %U\n", i, r)
	}
	fmt.Println(utf8.ValidString(s[:2]))
	b := []byte(s)
	b[0] = 'B'
	snapshot := string(b)
	b[0] = 'C'
	fmt.Println(s, snapshot, string(b))
	fmt.Println(string(rune(65)), strconv.Itoa(65))
}

func invalidText() {
	s := "\xffA"
	fmt.Println(utf8.ValidString(s))
	for i, r := range s {
		fmt.Printf("%d %U\n", i, r)
	}
	fmt.Println(utf8.RuneCountInString("é"), utf8.RuneCountInString("e\u0301"))
	fmt.Println("é" == "e\u0301")
}

func main() {
	for _, demo := range []struct {
		name string
		run  func()
	}{
		{"basics", basics}, {"copying", copying},
		{"length and capacity", lengthAndCapacity}, {"sharing", sharing},
		{"growth", growth}, {"map basics", mapBasics}, {"map values", mapValues},
		{"text units", textUnits}, {"invalid text", invalidText},
	} {
		fmt.Println("==", demo.name, "==")
		demo.run()
	}
}
