<?php

namespace svile\sw;

use pocketmine\event\Listener;

use pocketmine\event\entity\EntityDamageByEntityEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\player\PlayerDeathEvent;
use pocketmine\event\player\PlayerInteractEvent;
use pocketmine\event\player\PlayerMoveEvent;
use pocketmine\event\player\PlayerQuitEvent;
use pocketmine\event\player\PlayerRespawnEvent;
use pocketmine\event\player\PlayerCommandPreprocessEvent;

use pocketmine\event\block\BlockBreakEvent;
use pocketmine\event\block\SignChangeEvent;
use pocketmine\event\block\BlockPlaceEvent;

use pocketmine\level\Position;
use pocketmine\level\Location;

use pocketmine\Player;
use pocketmine\Server;
use pocketmine\utils\TextFormat;
use pocketmine\math\Vector3;


class SWlistener implements Listener
{
    /** @var SWmain */
    private $pg;

    public function __construct(SWmain $plugin)
    {
        $this->pg = $plugin;
    }

    public function onSignChange(SignChangeEvent $ev)
    {
        if ($ev->getLine(0) != 'sw' || $ev->getPlayer()->isOp() == false)
            return;

        $SWname = TextFormat::clean(trim($ev->getLine(1)));
        if (!array_key_exists($SWname, $this->pg->arenas)) {
            $ev->getPlayer()->sendMessage('§8(§cОшибка§8) §fАрена §cне найена§f!');
            return;
        }

        if (in_array($SWname, $this->pg->signs)) {
            $ev->getPlayer()->sendMessage('§8(§bS§fW§8) §fТабличка для §eэтой §fарены уже §aсуществует§f! Используйте: §c/sw signdelete§f!');
            return;
        }

        $world = $ev->getPlayer()->getLevel()->getName();
        if ($world == $this->pg->arenas[$SWname]->getWorld()) {
            $ev->getPlayer()->sendMessage('§8(§bS§fW§8) §fВы §cне можете §aразместить §fтабличку на §eарене§f!');
            return;
        }

        if (!$this->pg->arenas[$SWname]->setSpawn(true, '')) {
            $ev->getPlayer()->sendMessage('§8(§bS§fW§8) §fНа §eэтой §fарене нехватает спавнов. Используйте: §a/sw setspawn§f!');
            return;
        }

        if (!$this->pg->setSign($SWname, ($ev->getBlock()->getX() + 0), ($ev->getBlock()->getY() + 0), ($ev->getBlock()->getZ() + 0), $world))
            $ev->getPlayer()->sendMessage('§8(§cОшибка§8) §fПроизошла §cошибка§f!');
        else
            $ev->getPlayer()->sendMessage('§8(§bS§fW§8) §fТабличка успешно §bсоздана§f!');

        $format = new \pocketmine\utils\Config($this->pg->getDataFolder() . 'sign_format.yml', 2, [
            '1st line' => '§bSky§fWars',
            '2nd line' => '§e{SWNAME}',
        ]);
        $ev->setLine(0, $format->get('1st line', '§bSky§fWars'));
        $ev->setLine(1, str_replace('{SWNAME}', $SWname, $format->get('2nd line', '§e{SWNAME}')));
        $ev->setLine(2, '0' . '/' . $this->pg->arenas[$SWname]->getSlot());
        $ev->setLine(3, '§fTap to join');
        $this->pg->refreshSigns(true);
        unset($SWname, $world);
    }

    public function onInteract(PlayerInteractEvent $ev)
    {
        $item = $ev->getItem();
        if($item->getId() == 355 && $item->getCustomName() == "§r§cLeave Game"){
             foreach ($this->pg->arenas as $a) {
                if ($a->inArena($ev->getPlayer()->getName())) {
                    $a->quit($ev->getPlayer()->getName(), true);
                    $ev->setCancelled();
                    return;
                }
            }
        }

        if ($ev->getAction() !== PlayerInteractEvent::RIGHT_CLICK_BLOCK)
            return;

        foreach ($this->pg->arenas as $a) {
            if ($a->inArena($ev->getPlayer()->getName())) {
                if ($a->GAME_STATE == 0)
                    $ev->setCancelled();
                return;
            }
        }

        $key = $ev->getBlock()->x . ':' . $ev->getBlock()->y . ':' . $ev->getBlock()->z . ':' . $ev->getBlock()->getLevel()->getName();
        if (array_key_exists($key, $this->pg->signs))
            $this->pg->arenas[$this->pg->signs[$key]]->join($ev->getPlayer());
        unset($key);
    }

    public function onMove(PlayerMoveEvent $ev)
    {
        foreach ($this->pg->arenas as $a) {
            if ($a->inArena($ev->getPlayer()->getName())) {
                if ($a->GAME_STATE == 0) {
                    $spawn = $a->getWorld(true, $ev->getPlayer()->getName());
                    if ($ev->getPlayer()->getPosition()->distanceSquared(new Position($spawn['x'], $spawn['y'], $spawn['z'])) > 4)
                        $ev->setTo(new Location($spawn['x'], $spawn['y'], $spawn['z']));
                    break;
                }
                if ($a->void >= $ev->getPlayer()->getFloorY() && $ev->getPlayer()->isAlive()) {
                    $event = new EntityDamageEvent($ev->getPlayer(), EntityDamageEvent::CAUSE_VOID, 10);
                    $ev->getPlayer()->attack($event->getFinalDamage(), $event);
                    unset($event);
                }
                break;
            }
        }

        if ($this->pg->configs['sign.knockBack']) {
            foreach ($this->pg->signs as $key => $val) {
                $ex = explode(':', $key);
                $pl = $ev->getPlayer();
                if ($pl->getLevel()->getName() == $ex[3]) {
                    $x = (int)$pl->getFloorX();
                    $y = (int)$pl->getFloorY();
                    $z = (int)$pl->getFloorZ();
                    $radius = (int)$this->pg->configs['knockBack.radius.from.sign'];
                    if (($x >= ($ex[0] - $radius) && $x <= ($ex[0] + $radius)) && ($z >= ($ex[2] - $radius) && $z <= ($ex[2] + $radius)) && ($y >= ($ex[1] - $radius) && $y <= ($ex[1] + $radius))) {
                        $block = $pl->getLevel()->getBlock(new Vector3($ex[0], $ex[1], $ex[2]));
                        if ($block->getId() != 63 && $block->getId() != 68)
                            break;
                        $i = (int)$this->pg->configs['knockBack.intensity'];
                        if ($this->pg->configs['knockBack.follow.sign.direction']) {
                            switch ($block->getId()):
                                case 68:
                                    switch ($block->getDamage()) {
                                        case 3:
                                            $yaw = 0;
                                            break;
                                        case 4:
                                            $yaw = 0x5a;
                                            break;
                                        case 2:
                                            $yaw = 0xb4;
                                            break;
                                        case 5:
                                            $yaw = 0x10e;
                                            break;
                                        default:
                                            $yaw = 0;
                                            break;
                                    }
                                    break;
                                case 63:
                                    switch ($block->getDamage()) {
                                        case 0:
                                            $yaw = 0;
                                            break;
                                        case 1:
                                            $yaw = 22.5;
                                            break;
                                        case 2:
                                            $yaw = 0x2d;
                                            break;
                                        case 3:
                                            $yaw = 67.5;
                                            break;
                                        case 4:
                                            $yaw = 0x5a;
                                            break;
                                        case 5:
                                            $yaw = 112.5;
                                            break;
                                        case 6:
                                            $yaw = 0x87;
                                            break;
                                        case 7:
                                            $yaw = 157.5;
                                            break;
                                        case 8:
                                            $yaw = 0xb4;
                                            break;
                                        case 9:
                                            $yaw = 202.5;
                                            break;
                                        case 10:
                                            $yaw = 0xe1;
                                            break;
                                        case 11:
                                            $yaw = 247.5;
                                            break;
                                        case 12:
                                            $yaw = 0x10e;
                                            break;
                                        case 13:
                                            $yaw = 292.5;
                                            break;
                                        case 14:
                                            $yaw = 0x13b;
                                            break;
                                        case 15:
                                            $yaw = 337.5;
                                            break;
                                        default:
                                            $yaw = 0;
                                            break;
                                    }
                                    break;
                                default:
                                    $yaw = 0;
                            endswitch;
                            $vector = (new Vector3(-sin(deg2rad($yaw)), 0, cos(deg2rad($yaw))))->normalize();
                            $pl->knockBack($pl, 0, $vector->x, $vector->z, ($i / 0xa));
                        } else {
                            $pl->knockBack($pl, 0, ($pl->x - ($block->x + 0.5)), ($pl->z - ($block->z + 0.5)), ($i / 0xa));
                        }
                        break;
                    }
                    unset($ex, $pl, $x, $y, $z, $radius, $block, $i, $yaw);
                }
            }
        }
    }

    public function onQuit(PlayerQuitEvent $ev)
    {
        foreach ($this->pg->arenas as $a) {
            if ($a->quit($ev->getPlayer()->getName(), true))
                break;
        }
    }

    public function onDeath(PlayerDeathEvent $ev)
    {
        foreach ($this->pg->arenas as $a) {
            if ($a->quit($ev->getEntity()->getName())) {
                $ev->setDeathMessage('');
                if (($ev->getEntity()->getLastDamageCause() instanceof EntityDamageByEntityEvent) && $ev->getEntity()->getLastDamageCause()->getDamager() instanceof \pocketmine\Player) {
                    foreach ($this->pg->getServer()->getLevelByName($a->getWorld())->getPlayers() as $p) {
                        $p->sendMessage(str_replace('{COUNT}', '[' . $a->getSlot(true) . '/' . $a->getSlot() . ']', str_replace('{KILLER}', $ev->getEntity()->getLastDamageCause()->getDamager()->getName(), str_replace('{PLAYER}', $ev->getEntity()->getName(), $this->pg->lang['player.kill']))));
$p->sendPopup("§fThere are §e" . $a->getSlot(true) . " §fplayers remaining!");
                    }
                } elseif ($ev->getEntity()->getLastDamageCause()->getCause() == EntityDamageEvent::CAUSE_VOID) {
                    foreach ($this->pg->getServer()->getLevelByName($a->getWorld())->getPlayers() as $p) {
             
 $p->sendMessage(str_replace('{COUNT}', '[' . $a->getSlot(true) . '/' . $a->getSlot() . ']', str_replace('{PLAYER}', $ev->getEntity()->getName(), $this->pg->lang['void.kill'])));
$p->sendPopup("§fThere are §e" . $a->getSlot(true) . " §fplayers remaining!");
                    }
                    } elseif ($ev->getEntity()->getLastDamageCause()->getCause() == EntityDamageEvent::CAUSE_FALL) {
                    foreach ($this->pg->getServer()->getLevelByName($a->getWorld())->getPlayers() as $p) {
             
 $p->sendMessage(str_replace('{COUNT}', '[' . $a->getSlot(true) . '/' . $a->getSlot() . ']', str_replace('{PLAYER}', $ev->getEntity()->getName(), $this->pg->lang['fall.kill'])));
$p->sendPopup("§fThere are §e" . $a->getSlot(true) . " §fplayers remaining!");
                    }
                } else {
                    foreach ($this->pg->getServer()->getLevelByName($a->getWorld())->getPlayers() as $p) {
                        $p->sendMessage(str_replace('{COUNT}', '[' . $a->getSlot(true) . '/' . $a->getSlot() . ']', str_replace('{PLAYER}', $ev->getEntity()->getName(), $this->pg->lang['game.left'])));
$p->sendPopup("§fThere are §e" . $a->getSlot(true) . " §fplayers remaining!");
                    }
                }
                if (!$this->pg->configs['drops.in.arena'])
                    $ev->setDrops([]);
                break;
            }
        }
    }

    public function onDamage(EntityDamageEvent $ev)
    {
        foreach ($this->pg->arenas as $a) {
            if ($ev->getEntity() instanceof Player) {
                if ($a->inArena($ev->getEntity()->getName())) {
                    if ($ev->getCause() == 0b1111 && $this->pg->configs['starvation.can.damage.inArena.players'] == false)
                        $ev->setCancelled();
                    if ($a->GAME_STATE == 0)
                        $ev->setCancelled();
                    break;
                }
            }
        }
    }

    public function onRespawn(PlayerRespawnEvent $ev)
    {
        if ($this->pg->configs['always.spawn.in.defaultLevel'])
            $ev->setRespawnPosition($this->pg->getServer()->getDefaultLevel()->getSpawnLocation());
        //Removes player things
        if ($this->pg->configs['clear.inventory.on.respawn&join'])
            $ev->getPlayer()->getInventory()->clearAll();
        if ($this->pg->configs['clear.effects.on.respawn&join'])
            $ev->getPlayer()->removeAllEffects();
    }

    public function onBreak(BlockBreakEvent $ev)
    {
        foreach ($this->pg->arenas as $a) {
            if ($a->inArena($ev->getPlayer()->getName())) {
                if ($a->GAME_STATE == 0)
                    $ev->setCancelled();
                break;
            }
        }
        if (!$ev->getPlayer()->isOp()) return;
        $key = (($ev->getBlock()->getX() + 0) . ':' . ($ev->getBlock()->getY() + 0) . ':' . ($ev->getBlock()->getZ() + 0) . ':' . $ev->getPlayer()->getLevel()->getName());
        if (array_key_exists($key, $this->pg->signs)) {
            $ev->setCancelled(true);
            return
            $this->pg->arenas[$this->pg->signs[$key]]->stop();
            $ev->getPlayer()->sendMessage('§8(§bS§fW§8) §fАрена §eперезагружается§f!');
            if ($this->pg->setSign($this->pg->signs[$key], 0, 0, 0, 'world', true, false)) {
                $ev->getPlayer()->sendMessage('§8(§bS§fW§8) §fТабличка успешно §cудалена§f!');
            } else {
                $ev->getPlayer()->sendMessage('§8(§cОшибка§8) §fПроизошла §cошибка§f!');
            }
        }
        unset($key);
    }

    public function onPlace(BlockPlaceEvent $ev)
    {
        foreach ($this->pg->arenas as $a) {
            if ($a->inArena($ev->getPlayer()->getName())) {
                if ($a->GAME_STATE == 0)
                    $ev->setCancelled();
                break;
            }
        }
    }

    public function onCommand(PlayerCommandPreprocessEvent $ev)
    {
        $command = strtolower($ev->getMessage());
        if ($command{0} == '/') {
            $command = explode(' ', $command)[0];
            foreach ($this->pg->arenas as $a) {
                if ($a->inArena($ev->getPlayer()->getName())) {
                    if (in_array($command, $this->pg->configs['banned.commands.while.in.game'])) {
                        $ev->getPlayer()->sendMessage($this->pg->lang['banned.command.msg']);
                        $ev->setCancelled();
                    }
                    break;
                }
            }
        }
        unset($command);
    }
}