<?php declare(strict_types = 0);
/*
** Copyright (C) 2021-2026 initMAX s.r.o.
**
** This program is free software: you can redistribute it and/or modify it under the terms of
** the GNU Affero General Public License as published by the Free Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
** without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
** See the GNU Affero General Public License for more details.
**
** You should have received a copy of the GNU Affero General Public License along with this program.
** If not, see <https://www.gnu.org/licenses/>.
**/

namespace Modules\TetrisMAX\Includes;

/**
 * The seven pieces: colour, spawn chance and the four rotation states of each.
 *
 * PLAIN CLASS, NOT AN ENUM, ON PURPOSE. This used to be a backed enum built
 * with match() and ReflectionEnum - PHP 8.1 syntax. Zabbix 6.0 and 6.2 run on
 * PHP 7.4, and even Zabbix 7.0 is supported down to PHP 8.0, so the enum put a
 * floor under the widget that had nothing to do with what the widget does: it
 * hands the browser a table of shapes. Rewritten as a table.
 *
 * The exported SHAPE is unchanged - `{type, getColor, spawnChance, rotations}`
 * per piece, keyed by the letter - because assets/js/class.widget.js reads
 * exactly those names off the JSON and a rename would empty the board.
 */
final class Tetrominoes {

	/**
	 * Colour index per piece. The CSS picks the gradient off `data-value`
	 * (see assets/css/widget.css), so these are the same numbers the
	 * stylesheet names, as strings - which is what the enum's `: string`
	 * return type coerced them to, and what the client already receives.
	 */
	private const COLORS = [
		'I' => '1',
		'O' => '4',
		'T' => '6',
		'S' => '5',
		'Z' => '7',
		'J' => '2',
		'L' => '3'
	];

	/** Relative spawn chance in percent. The seven must sum to 100. */
	private const SPAWN_CHANCES = [
		'I' => 10.0,
		'O' => 12.0,
		'T' => 18.0,
		'S' => 14.0,
		'Z' => 14.0,
		'J' => 16.0,
		'L' => 16.0
	];

	/**
	 * Four rotation states per piece; each state is a list of [x, y] pairs.
	 * The origin is the top-left of the piece's bounding box, matching the
	 * board coordinates class.gameboard.js works in.
	 */
	private const ROTATIONS = [
		'I' => [
			[[0, 1], [1, 1], [2, 1], [3, 1]],
			[[2, 0], [2, 1], [2, 2], [2, 3]],
			[[0, 2], [1, 2], [2, 2], [3, 2]],
			[[1, 0], [1, 1], [1, 2], [1, 3]]
		],
		'O' => [
			[[1, 0], [2, 0], [1, 1], [2, 1]],
			[[1, 0], [2, 0], [1, 1], [2, 1]],
			[[1, 0], [2, 0], [1, 1], [2, 1]],
			[[1, 0], [2, 0], [1, 1], [2, 1]]
		],
		'T' => [
			[[1, 0], [0, 1], [1, 1], [2, 1]],
			[[1, 0], [1, 1], [2, 1], [1, 2]],
			[[0, 1], [1, 1], [2, 1], [1, 2]],
			[[1, 0], [0, 1], [1, 1], [1, 2]]
		],
		'S' => [
			[[1, 0], [2, 0], [0, 1], [1, 1]],
			[[1, 0], [1, 1], [2, 1], [2, 2]],
			[[1, 1], [2, 1], [0, 2], [1, 2]],
			[[0, 0], [0, 1], [1, 1], [1, 2]]
		],
		'Z' => [
			[[0, 0], [1, 0], [1, 1], [2, 1]],
			[[2, 0], [1, 1], [2, 1], [1, 2]],
			[[0, 1], [1, 1], [1, 2], [2, 2]],
			[[1, 0], [0, 1], [1, 1], [0, 2]]
		],
		'J' => [
			[[0, 0], [0, 1], [1, 1], [2, 1]],
			[[1, 0], [2, 0], [1, 1], [1, 2]],
			[[0, 1], [1, 1], [2, 1], [2, 2]],
			[[1, 0], [0, 2], [1, 1], [1, 2]]
		],
		'L' => [
			[[2, 0], [0, 1], [1, 1], [2, 1]],
			[[1, 0], [1, 1], [1, 2], [2, 2]],
			[[0, 1], [1, 1], [2, 1], [0, 2]],
			[[0, 0], [1, 0], [1, 1], [1, 2]]
		]
	];

	/**
	 * Every piece, in the shape the client expects.
	 *
	 * @return array<string,array>
	 */
	public static function definitionMap(): array {
		$result = [];

		foreach (self::COLORS as $type => $color) {
			$result[$type] = [
				'type' => $type,
				'getColor' => $color,
				'spawnChance' => self::SPAWN_CHANCES[$type],
				'rotations' => self::ROTATIONS[$type]
			];
		}

		return $result;
	}
}
