package main

import (
	"fmt"
	"strings"

	"github.com/davecgh/go-spew/spew"
)

type Item struct {
	Prev *Item
	Next *Item
	Val  int
}

type Circular struct {
	Root    *Item
	Current *Item
}

func NewCircular() *Circular {
	i := Item{
		Val: 0,
	}
	i.Prev = &i
	i.Next = &i
	return &Circular{
		Current: &i,
		Root:    &i,
	}
}

func (c *Circular) Add(i int) {
	it := Item{
		Prev: c.Current,
		Next: c.Current.Next,
		Val:  i,
	}
	c.Current.Next.Prev = &it
	c.Current.Next = &it
	c.Current = &it
}

func (c *Circular) Pop() int {
	prev := c.Current.Prev
	next := c.Current.Next
	prev.Next = next
	next.Prev = prev
	val := c.Current.Val
	c.Current = next
	return val
}

func (c *Circular) Rotate(i int) {
	for {
		if i > 0 {
			c.Current = c.Current.Next
			i--
		} else if i < 0 {
			c.Current = c.Current.Prev
			i++
		} else {
			break
		}
	}
}

func (c Circular) String() string {
	output := strings.Builder{}
	it := c.Root
	for {
		if it == c.Current {
			output.WriteString(fmt.Sprintf("\t(%3d)", it.Val))
		} else {
			output.WriteString(fmt.Sprintf("\t%4d", it.Val))
		}
		it = it.Next
		if it == c.Root {
			break
		}
	}
	return output.String()
}

type Puzzle struct {
	Players    int
	LastMarble int
	Marbles    *Circular
}

func (p *Puzzle) Solution1(debug bool) int {
	players := make([]int, p.Players)

	if debug {
		fmt.Printf("[--]%s\n", p.Marbles)
	}
	pnum := 0
	for t := 1; t <= p.LastMarble; t++ {
		if t%23 == 0 {
			p.Marbles.Rotate(-7)
			players[pnum] += t + p.Marbles.Pop()
		} else {
			p.Marbles.Rotate(1)
			p.Marbles.Add(t)
		}
		if debug {
			fmt.Printf("[%2d]%s\n", pnum+1, p.Marbles)
		}
		pnum++
		if pnum >= p.Players {
			pnum = 0
		}
	}

	if debug {
		spew.Dump(players)
	}

	highest := 0
	for _, p := range players {
		if p > highest {
			highest = p
		}
	}
	return highest
}

func (p *Puzzle) Solution2() int {
	return 0
}

func main() {
	p := Puzzle{
		//Players:    9,
		// LastMarble: 25,
		Players:    439,
		LastMarble: 7130700,
		Marbles:    NewCircular(),
	}

	fmt.Println(p.Solution1(false))
	fmt.Println(p.Solution2())
}