<?php

namespace bedwars\entity\api;

use pocketmine\network\protocol\AddPlayerPacket;
use pocketmine\network\protocol\AddEntityPacket;
use pocketmine\network\protocol\RemoveEntityPacket;
use pocketmine\network\protocol\RemovePlayerPacket;
use pocketmine\network\protocol\PlayerListPacket;
use pocketmine\utils\UUID;

use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\StringTag;

use pocketmine\network\protocol\SetEntityDataPacket;

use pocketmine\entity\Human;
use pocketmine\entity\Entity;

use pocketmine\Player;

class HumanAPI extends Human {

	/**
	 * @param Player $player
	 */
	public function addPlayerList(Player $player) {
		$pk = new PlayerListPacket();
		$pk->type = PlayerListPacket::TYPE_ADD;
		$pk->entries[] = [$this->getUniqueId(), $this->getId(), $this->getName(), $this->getSkinId(), $this->getSkinData()];
		$player->dataPacket($pk);
	}

	/**
	 * @param Player $player
	 */
	public function removePlayerList(Player $player) {
		$pk = new PlayerListPacket();
		$pk->type = PlayerListPacket::TYPE_REMOVE;
		$pk->entries[] = [$this->getUniqueId()];
		$player->dataPacket($pk);
	}

	public function initEntity() {
		parent::initEntity();
		
		if (isset($this->namedtag->Name)) {
			$lines = explode("\n", $this->namedtag["Name"]);

			if (count($lines) > 0) {
				$this->addLines($lines);
			}
		}
	}
	
	/**
	 * @param array $lines
	 * @return bool
	 */
	public function addLines(array $lines) : bool {
		if (empty($this->getDataProperty(2)) === false) {
			$this->setDataProperty(2, self::DATA_TYPE_STRING, null);
		}
		
		$this->namedtag->Name = new StringTag("Name", implode("\n", $lines));
		
		$transform = $this->transform($lines);

		if ($transform !== false) {
			$parent = $this->namedtag->Parent;
			$toRemove = [];
			
			foreach ($transform as $key => $line) {
				if (isset($parent->{$key})) {
					if ($this->updateLine($key, ...$line) === false) {
						$this->clearLines($player);
						$this->addLines($lines);
						return false;
					}
				} else {
					$this->addLine($key, ...$line);
				}
				$toRemove[] = $key;
			}

			foreach ($parent as $key => $line) {
				if (isset($toRemove[$key]) === false) {
					$this->removeLine($key);
				}
			}
			return true;
		} else {
			return false;
		}
	}

	/**
	 * @param string $name
	 * @return array|false
	 */
	public function transform(array $lines) {
		$lines = array_reverse($lines);

		if (count($lines) > 0) {
			$list = [];
			$y = $this->y - 0.30;

			foreach ($lines as $line) {
				$y += 0.29;
				$list[] = [$line, $y];
			}
			return $list;
		}
		return false;
	}

	public function addLine($key, $text, $y) {
		$line = Line::createLine($this->chunk, $key, $text, $this->id, $this->x, $y, $this->z);
		$line->spawnToAll();
		$this->namedtag->Parent->{$key} = $line->getId();
	}

	public function updateLine($key, $text, $y) : bool {
		if (isset($this->namedtag->Parent->{$key})) {
			$id = $this->namedtag->Parent->{$key};
			$entity = $this->level->getEntity($id);

			if ($entity instanceof Line) {
				$oldText = $entity->getDataProperty(2);
				
				if ($oldText != $text) {
					$entity->setDataProperty(2, Line::DATA_TYPE_STRING, $text); 
				}
				return true;
			} else {
				return false;
			}
		} else {
			return false;
		}
	}

	public function clearLines() {
		foreach ($this->namedtag->Parent as $key => $id) {
			$this->removeLine($key);
		}
	}

	public function respawnToAll() {
		parent::respawnToAll();

		foreach ($this->namedtag->Parent as $key => $id) {
			$entity = $this->level->getEntity($id);

			if ($entity instanceof Line) {
				$entity->respawnToAll();
			}
		}
	}

	public function removeLine($key) : bool {
		if (isset($this->namedtag->Parent->{$key})) {
			$id = $this->namedtag->Parent->{$key};
			$entity = $this->level->getEntity($id);
			unset($this->namedtag->Parent->{$key});
			if ($entity instanceof Line) {
				$entity->close();
				return true;
			} else {
				return false;
			}
		} else {
			return false;
		}
	}

	public function close() {
		$this->clearLines();
		parent::close();
	}
}