package grid

import (
	"fmt"
	"strings"
)

// Cell represents a single cell in the grid.
type Cell struct {
	R rune
	// Color
}

// Grid is the struct holding the grid information.
type Grid struct {
	Cells  []Cell
	Width  int
	Height int
	Label  string
}

// FromRunes creates a new grid from a rune slice.
func FromRunes(runes []rune, width, height int) Grid {
	g := Grid{
		Width:  width,
		Height: height,
	}
	g.Cells = make([]Cell, len(runes))
	for i, r := range runes {
		g.Cells[i].R = r
	}
	return g
}

// TODO: Grow.
// TODO: Shrink.
// TODO: Cellmap for prettyprints.

// FromRunes reads in cells from a rune-slice.
// NOTE: Does not update width/height.
func (g *Grid) FromRunes(runes []rune) {
	g.Cells = make([]Cell, len(runes))
	for i, r := range runes {
		g.Cells[i].R = r
	}
}

// Clone returns a deep copy of the grid.
func (g *Grid) Clone() *Grid {
	clone := Grid{
		Cells:  make([]Cell, len(g.Cells)),
		Width:  g.Width,
		Height: g.Height,
		Label:  g.Label,
	}
	copy(clone.Cells, g.Cells)
	return &clone
}

// Set sets a cell at location.
func (g *Grid) Set(x, y int, c Cell) {
	g.Cells[(y*g.Width)+x] = c
}

// Get gets a cell at location.
func (g *Grid) Get(x, y int) Cell {
	return g.Cells[(y*g.Width)+x]
}

func (g Grid) String() string {
	var result strings.Builder
	result.Grow((g.Width * g.Height) * 2)

	fmt.Fprintf(&result, "╭")
	fmt.Fprintf(&result, "─ %s ─", g.Label)
	for x := len(g.Label) + 4; x < g.Width+2; x++ {
		fmt.Fprintf(&result, "─")
	}
	fmt.Fprintf(&result, "╮\n")

	for y := 0; y < g.Height; y++ {
		fmt.Fprintf(&result, "│ ")

		i := y * g.Width
		for x := 0; x < g.Width; x++ {
			r := g.Cells[i+x].R
			if r < ' ' {
				r = ' '
			}
			fmt.Fprintf(&result, "%c", r)
		}

		fmt.Fprintf(&result, " │\n")
	}

	fmt.Fprintf(&result, "╰")
	for x := 1; x < g.Width+3; x++ {
		fmt.Fprintf(&result, "─")
	}
	fmt.Fprintf(&result, "╯")

	return result.String()
}