<?php

namespace bedwars\game;

use pocketmine\level\sound\EndermanTeleportSound;
use pocketmine\level\sound\ButtonClickSound;
use bedwars\Mod_TopModule;
use pocketmine\Server;
use pocketmine\Player;
use pocketmine\level\Level;
use pocketmine\level\Position;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\DoubleTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\FloatTag;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\item\enchantment\Enchantment;
use pocketmine\entity\Effect;

use bedwars\util\Cage;
use bedwars\BedWars;
use bedwars\util\Team;
use bedwars\util\Bed;
use bedwars\util\Generetor;

class Game extends BasicGame {
    
    /**
     * @param int $currentTicks
     */
    public function onUpdate($currentTicks = 0) {
        $modec = self::MODE_COUNT[$this->mode];
        
        switch ($this->index) {
            case 0: //empty
                if ($this->getSlot(true) > $modec) {
                    $this->index++;
                }
                
                $this->print("§c§lWaiting For Players...§r ", 2);
                break;
            
            case 1: //players
                if ($this->getSlot(true) <= $modec) {
                    $this->index--;
                    $this->time = 15;
                }
                
                $this->print("§2§lSTARTING MATCH IN...§r§2  " . date("s", $this->time--) . "s", 2);
                
                if ($this->time <= 0) {
                    $this->index++;
                    $this->time = 10;
                    
                    foreach ($this->teams as $name => $team) {
                        if (!($team instanceof Team)) {
                            continue;
                        }
                        
                        if ($team->getCount() <= 0) {
                            unset($this->teams[$name]);
                            continue;
                        }
                        
                        if (isset($this->defaultTeams[$name])) {
                            $args = $this->defaultTeams[$name];

                            $args = explode(":", $args['spawns']);
                            $args[1] += 15;
                    
                            if ($this->level instanceof Level) {
                                $position = new Position(...$args);
                                $position->setLevel($this->level);
                        
                                Cage::spawn($position, 'iron', true);
                            }
                        }
                        
                        $this->teleportPlayersToSpawn($team->getPlayers(), $team);
                    }
                }
                break;
            
            case 2: //starting
                if (count($this->players) <= 0) {
                    $this->reset();
                    break;
                }

                if ($this->time > 5) {
                    $this->print("§l§e" . date("s", $this->time--) . "§r§es", 3);
                } else if ($this->time > 0) {
                    $this->print("§l§c" . date("s", $this->time--) . "§r§cs", 3);

                    if ($this->level instanceof Level) {
                        foreach ($this->level->getPlayers() as $player) {
                            $player->level->addSound((new ButtonClickSound($player)), [$player]);
                        }
                    }
                } else {
                    $this->index++;
                    $this->time = 30000; //50 minutes
                    
                    //TODO:
                    if ($this->bed instanceof Bed) {
                        $this->bed->start();
                    }
                    
                    if ($this->generetor instanceof Generetor) {
                        $this->generetor->start();
                    }
                    
                    $this->print("§l§aGood Luck!", 3);
                    
                    foreach ($this->teams as $name => $team) {
                        if ($team == null) {
                            continue;
                        }
                        
                        if (isset($this->defaultTeams[$name])) {
                            $args = $this->defaultTeams[$name];

                            $args = explode(":", $args['spawns']);
                            $args[1] += 15;
                    
                            if ($this->level instanceof Level) {
                                $position = new Position(...$args);
                                $position->setLevel($this->level);
                        
                                Cage::spawn($position, 'air', true);
                            }
                        }
                    }
                }
                break;
            
            case 3: //run
                if (count($this->players) <= 0) {
                    $this->backupMap();
                    $this->reset();
                    break;
                }

                if ($this->generetor instanceof Generetor) {
                    $this->generetor->run();
                }

                foreach ($this->respawn as $key => &$value) {
                    if ($value[0] instanceof Player) {
                        if ($value[1]-- > 0) {
                            $value[0]->sendTip("§r§l§cYou Died!§r\n§eYou Will Be Respawned in: " . $value[1] . "§r§es§r\n\n\n\n");
                        } else {
                            $this->respawnPlayer($value[0], $this->getTeam($value[0]->getName()));
                            $this->setContents($value[0], 1);
                            unset($this->respawn[$key]);
                        }
                    }
                }
                
                $bar = "";
                
                foreach ($this->teams as $name => $team) {
                    $color = $this->getColor($name);
                    $count = $team->getNecCount();
                    $status = $team->isAlive() ? "√" : ($count > 0 ? $count : "x");
                    $bar .= "{$color}[{$status}] $name ";
                }
                
                foreach ($this->getPlayers() as $name => $player) {
                    $name = $player->getName();
                    
                    if (($player == null) or !(isset($this->players[$name])) or isset($this->respawn[$name]))
                        continue;
                        
                    $playerTeam = $this->getTeam($player->getName());
                    $team = $playerTeam->getName();
                    $player->sendPopup(str_replace($team, $team . "§7 (You)", $bar));
                }
                
                if ($this->time-- <= 0) {
                    //TIME LEFT:
                }
                
                $alives = array();
                
                foreach ($this->teams as $name => $team) {
                    if ($team->getNecCount() > 0) {
                        $alives[] = $team;
                    }
                }
                
                if (($this->getSlot(true) <= $modec) or (count($alives) <= 1)) {
                    $team = $alives[0];
                    $players = $team->getPlayers();
                    
                    if ($modec > 1) {
                        $message = "§r§l§aThe Team " . $this->getColor($team->getName()) . ucfirst($team->getName()) . "§r§l§a Won!§r\n\n\n\n";
                        $this->team = $team;
                    } else {
                        if (count($players) > 0) {
                            $name = array_keys($players)[0];
                            
                            $nametag = $this->getColor($team->getName()) . "[" . ucfirst($team->getName(){0}) . "]§r §f" . $name;
                            $message = "§r§l§a" . $nametag . "§r§a Won The Match!";
                        }
                    }

                    foreach ($players as $player) {
                        if ($player instanceof Player) {
                            $this->setContents($player, 4);
                        }
                    }
                    
                    $plugin = BedWars::$loaded;
                    
                    foreach ($players as $player) {
                        if (!($player instanceof Player)) {
                            continue;
                        }
                        $key = $player->getName();
                        $wins = 1;

                        if ($plugin->topWins->exists($key)) {
                            $wins += $plugin->topWins->get($key);
                        }
                        $plugin->topWins->set($key, $wins);
                    }
                    $plugin->topWins->save(true);
                    $plugin->MOD_top_module->onWin($player);
                    $plugin->MOD_top_module->reloadData();
                    
                    $this->index++;
                    $this->message = $message;
                    $this->player = $players;
                    $this->print($message, 3);
                    break;
                }
                break;
            
            case 4: //Finishing
                if (count($this->players) <= 0) {
                    $this->backupMap();
                    $this->reset();
                    break;
                }
                
                if (--$this->returnTime > 0) {
                    if (is_string($this->message)) {
                        $this->print($this->message . "§r\n\n\n\n§7Returning to the lobby in: §f" . $this->returnTime . "§7s!", 3, false);
                    }
                    
                    if (is_array($this->player)) {
                        foreach ($this->player as $name => $player) {
                            if (!($player instanceof Player)) {
                                unset($this->player[$name]);
                                continue;
                            }
                            
                            if (isset($this->players[$player->getName()])) {
                                $player->sendTip("§r§l§6          Victory!§r\n§7          You Won!\n\n\n\n§7Returning to lobby in: §f" . $this->returnTime . "§7s!");
                                $this->addParticle($player);
                            } else {
                                unset($this->players[$player->getName()]);
                            }
                        }
                    }
                } else {
                    $this->backupMap();
                    $this->reset();
                }
                break;
        }
        
    }
    
    /**
     * @param Player $player
     * @param bool   $message
     */
    public function join(Player $player, bool $message = true) {
        foreach (BedWars::$loaded->arenas as $game) {
            if ($game instanceof Game) {
                if (isset($game->players[$player->getName()])) {
                    return 2;
                    break;
                }
            }
        }

        if ($this->check()) {
            return false;
        }

        if ($this->index < 2) {
            if ($this->getSlot(true) >= $this->getSlot()) {
                return 1;
            }

            $team = null;

            foreach ($this->defaultTeams as $key => $value) {
                if (isset($this->teams[$key])) {
                    $teamData = $this->teams[$key];
                    $count = $teamData->getCount();
                    $modec = self::MODE_COUNT[$this->mode];

                    if ($count >= $modec) {
                        continue;
                    }

                    $teamData->addPlayer($player);

                    $team = $teamData;
                    break;
                }

                $teamData = new Team($key);
                $teamData->addPlayer($player);

                $team = $teamData;
                break;
            }

            if ($team instanceof Team) {
                $this->players[$player->getName()] = $team->getName();
                $this->teams[$team->getName()] = $team;

                $this->teleportToHub($player);
                
                if ($message) {
                    $player->sendMessage("§r§a§oEntering...");
                }
                
                $this->print($player->getNameTag() . " §7Entered the party");
                
                $player->sendMessage("§r§7§lYou§r§7 got put into the team " . $this->getColor($team->getName()) . ucfirst($team->getName()) . "§r§7!");
                
                $this->setContents($player, 0);
                $this->clearTrash();
                
                $party = $player->getServer()->getPluginManager()->getPlugin("PartyMenu");
                
                if ($party != null) {
                    $party->getParty($player)->pushToBW($this);
                }
                return true;
            } else {
                return 1;
            }
        } else {
            return 0;
        }
        return false;
    }
    
    public function check() : bool {
        //TODO:
        return false;
    }
    
    /**
     * @param Player $player
     */
    public function teleportToHub(Player $player) : bool {
        $hub = $this->getHub();
        
        if ($hub instanceof Level) {
            $args = $this->hub;
            $yaw = (int) $args[4];
            
            unset($args[3], $args[4]);
            
            $position = new Position(...$args);
            $position->setLevel($hub);
            
            $player->teleport($position, $yaw);
            
            $player->level->addSound((new EndermanTeleportSound($player)), [$player]);
            return true;
        }
        return false;
    }
    
    /**
     * @param Player $player
     * @param string $team 
     * @param bool $flying
     * @return bool
     */
    public function teleportToSpawn(Player $player, $team = null, bool $flying = false) : bool {
        if (($player == null) or !($this->level instanceof Level)) {
            return false;
        }
        
        if ($team == null) {
            $team = $this->getTeam($player->getName());
        }
        
        if (isset($this->defaultTeams[$team->getName()])) {
            $args = $this->defaultTeams[$team->getName()];

            $args = explode(":", $args['spawns']);
            $args[1]++;
            if ($flying)  {
                $args[1] += 15;
            }
                
            $position = new Position(...$args);
            $position->setLevel($this->level);
            $player->teleport($position);
            
            if ($flying) {
                //Cage::spawn($position, 'default', true);
            }
            return true;
        }
        return false;
    }
    
    /**
     * @param Player $player
     * @param string $team 
     * @param bool $flying
     * @return bool
     */
    public function respawnPlayer(Player $player, $team = null) : bool {
        if (($player == null) or !($this->level instanceof Level)) {
            return false;
        }
        
        if ($team == null) {
            $team = $this->getTeam($player->getName());
        }
        
        if ($team == null) return;
        
        if (isset($this->defaultTeams[$team->getName()])) {
            $args = $this->defaultTeams[$team->getName()];

            $args = explode(":", $args['ores']);
            $args[1]++;

            $position = new Position(...$args);
            $position->setLevel($this->level);
            $player->teleport($position);
            return true;
        }
        return false;
    }

    /** 
    * @param array $players
    * @param string $team
    */
    public function teleportPlayersToSpawn(array $players, $team) {
        foreach ($players as $player) {
            if ($player == null) {
                return;
            }
            
            $this->teleportToSpawn($player, $team, true);
            
            $player->level->addSound((new EndermanTeleportSound($player)), [$player]);
            
            $this->setContents($player, 1);
        }
    }
    
    /**
     * @param string $team
     * @param Player $player
     */
    public function updateItems(string $team, $player = null) {
        if (isset($this->teams[$team], $this->upgrade[$team])) {
            $players = array();
            $team = $this->teams[$team];
            
            if ($player instanceof Player) {
                $players[] = $player;
            } else {
                $players = $team->getPlayers();
            }
            
            foreach ($this->upgrade[$team->getName()] as $type => $level) {
                foreach ($players as $player) {
                    if (!($player instanceof Player))
                        continue;
                    
                    $inventory = $player->getInventory();
                    $contents = $inventory->getContents();
                    $forEnchant = null;
                    $forEffect = null;
                    
                    switch ($type) {
                        case 'miner':
                            $forEffect = 3;
                            break;
                        case 'sharp':
                            $forEnchant = 9;
                            break;
                        case 'armor':
                            $forEnchant = 0;
                            break;
                        case 'forca':
                            $forEffect = 5;
                            break;
                        case 'regen':
                            $forEffect = 10;
                            break;
                    }
                    
                    if ($forEnchant !== null) {
                        if ($forEnchant != 0) {
                            foreach ($contents as $slot => &$item) {
                                if (!($item->isTool())) {
                                    continue;
                                } 
                                if ($forEnchant == 9 and $item->isSword()) {
                                    $enchantment = Enchantment::getEnchantment($forEnchant);
                                    $enchantment->setLevel($level);
                                    $item->addEnchantment($enchantment);
                                }
                            } 
                            $inventory->setContents($contents);
                        } else {
                            $chestplate = $inventory->getChestplate();
                            $leggings = $inventory->getLeggings();
                            $enchantment = Enchantment::getEnchantment($forEnchant);
                            $enchantment->setLevel($level);
                            $chestplate->addEnchantment($enchantment);
                            $leggings->addEnchantment($enchantment);
                        
                            $inventory->setChestplate($chestplate);
                            $inventory->setLeggings($leggings);
                        }
                    } else if ($forEffect) {
                        $effect = Effect::getEffect($forEffect);
                        $effect->setVisible(false);
                        $effect->setDuration(Effect::MAX_DURATION);
                        $effect->setAmplifier($level);
                        $player->addEffect($effect);
                    }
                }
            }
        }
    }
    
    /**
     * @param Playe $player
     * @param int   $type
     */
    public function setContents(Player $player, int $type = -1) {
        $inventory = $player->getInventory();
        $inventory->clearAll();
        $contents = array();
        $armors = array();
        
        $gamemode = 0;
        $flying = false;
        $invisible = false;
        $player->setHealth($player->getMaxHealth());
        $player->setFood(20);
        $player->removeAllEffects();
        
        $count = count($this->defaultTeams);
        $color = $this->getDyeColor($this->getTeam($player->getName())->getName());
        switch ($type) {
            case 0:
                $gamemode = 2;
                $teams = Item::get(342, 0, ($count == 0 ? 1 : $count));
                $teams->setCustomName("§r§e§lTEAMS§r§f - §7Click To Select!");
                $namedtag = $teams->getNamedTag();
                $namedtag->Index = new IntTag("Index", 0);
                $teams->setNamedTag($namedtag);
                $contents[3] = $teams;
                
                $exit = Item::get(355);
                $exit->setCustomName("§r§c§lQuit§r§f - §7Click To Quit");
                $namedtag = $exit->getNamedTag();
                $namedtag->Index = new IntTag("Index", 1);
                $exit->setNamedTag($namedtag);
                $contents[7] = $exit;
                break;
            
            case 1:
                $sword = Item::get(268);
                $axe = null;
                $pickaxe = null;
                if (isset($this->tools[$player->getName()])) {
                    $tools = $this->tools[$player->getName()];
                    foreach ($tools as $key => $item) {
                        ${$key} = $item;
                    }
                }

                $contents[] = $sword;
                $contents[] = $axe;
                $contents[] = $pickaxe;
                
                $helmet = Item::get(298);
                $chestplate = Item::get(299);
                $leggings = Item::get(300);
                $boots = Item::get(301);
                
                if (isset($this->armors[$player->getName()])) {
                    $chestplate = $this->armors[$player->getName()][0];
                    $leggings = $this->armors[$player->getName()][1];
                } else {
                    $chestplate->setCustomColor($color);
                    $leggings->setCustomColor($color);
                }
                
                $helmet->setCustomColor($color);
                $boots->setCustomColor($color);
                
                $armors[] = $helmet;
                $armors[] = $chestplate;
                $armors[] = $leggings;
                $armors[] = $boots;
                
                $this->updateItems($this->getTeam($player->getName())->getName(), $player);
                break;
            case 2:
                $gamemode = 2;
                $invisible = true;
                $flying = true;
                $exit = Item::get(355);
                $exit->setCustomName("§r§c§lQuit§r§f - §7Click To Quit!");
                $namedtag = $exit->getNamedTag();
                $namedtag->Index = new IntTag("Index", 1);
                $exit->setNamedTag($namedtag);
                $contents[7] = $exit;
                break;
            
            case 3:
                $gamemode = 2;
                $flying = true;
                break;
            
            case 4:
                $gamemode = 2;
                $flying = true;
                $exit = Item::get(355);
                $exit->setCustomName("§r§c§lQuit§r§f - §7Click To Quit!");
                $namedtag = $exit->getNamedTag();
                $namedtag->Index = new IntTag("Index", 1);
                $exit->setNamedTag($namedtag);
                $contents[7] = $exit;
                break;
        }

        $player->setGamemode($gamemode);

        if (!$flying)
            $player->setMotion(new Vector3(0,-4,0));

        $player->setAllowFlight($flying);

        if ($invisible) {
            $effect = Effect::getEffect(Effect::INVISIBILITY);
            $effect->setDuration(Effect::MAX_DURATION);
            $effect->setAmplifier(1);
            $effect->setVisible(false);
            $player->addEffect($effect);
            
            $player->despawnFromAll();
        } else {
            $player->spawnToAll();
        }
        
        foreach ($contents as $slot => $item) {
            if ($item != null)
                $inventory->setItem($slot, $item);
        }
        
        foreach ($armors as $key => $armor) {
            if ($key == 0) {
                $inventory->setHelmet($armor);
            } else if ($key == 1) {
                $inventory->setChestplate($armor);
            } else if ($key == 2) {
                $inventory->setLeggings($armor);
            } else if($key == 3) {
                $inventory->setBoots($armor);
            }
        }
    }
    
}
?>