package game

import (
	"slices"

	"tetris/engine/graphics"
)

const (
	GRID_WIDTH  = 10
	GRID_HEIGHT = 16
)

type Grid [GRID_WIDTH * GRID_HEIGHT]Block

func (Grid) Width() int32 {
	return GRID_WIDTH
}

func (Grid) Height() int32 {
	return GRID_HEIGHT
}

func (g Grid) At(x, y byte) Block {
	return g[uint16(x)+(uint16(y)*GRID_WIDTH)]
}

func (g Grid) Tile(x, y byte) graphics.Tile {
	return g.At(x, y).Tile()
}

func (g *Grid) Set(x, y byte, c Block) {
	(*g)[uint16(x)+(uint16(y)*GRID_WIDTH)] = c
}

func (g *Grid) ClearFullLines() byte {
	completed := byte(0)
	for y := int(g.Height() - 1); y >= 0; y-- {
		if g.IsLineFull(byte(y)) {
			completed++
			g.ClearLine(byte(y))
		} else if completed > 0 {
			g.MoveLineDown(byte(y), completed)
		}
	}
	return completed
}

func (g *Grid) FullLines() []byte {
	lines := []byte{}
	for y := byte(0); y < byte(g.Height()); y++ {
		if g.IsLineFull(y) {
			lines = append(lines, y)
		}
	}
	return lines
}

func (g *Grid) IsLineFull(y byte) bool {
	for x := range byte(g.Width()) {
		if g.At(x, y) == BLOCK_EMPTY {
			return false
		}
	}
	return true
}

func (g *Grid) MoveLinesDown(rows ...byte) {
	completed := byte(0)
	for y := int(g.Height() - 1); y >= 0; y-- {
		if slices.Contains(rows, byte(y)) {
			completed++
		} else if completed > 0 {
			g.MoveLineDown(byte(y), completed)
		}
	}
}

func (g *Grid) MoveLineDown(y, num_lines byte) {
	w := uint16(g.Width())
	src := uint16(y) * w
	dst := uint16(y+num_lines) * w
	copy(g[dst:dst+w], g[src:src+w])
	clear(g[src : src+w])
}

func (g *Grid) ClearLine(y byte) {
	w := uint16(g.Width())
	n := uint16(y) * w
	clear(g[n : n+w])
}
