<?php


namespace App\Model\Services;


use App\Model\Entities\Game;
use App\Model\Entities\GameData\Mmorpg\Boss;
use App\Model\Entities\GameData\Mmorpg\Instance;
use App\Model\Entities\GameData\Mmorpg\InstanceMode;
use App\Model\Entities\GameData\Mmorpg\InstanceType;
use App\Model\Entities\Security\User;
use Kdyby\Doctrine\Dql\Join;
use Kdyby\Doctrine\EntityRepository;
use Kdyby\Doctrine\QueryBuilder;

class InstanceService extends BaseService
{
    /** @var EntityRepository */
    protected $instances;
    /** @var EntityRepository */
    protected $instanceTypes;
    /** @var EntityRepository */
    protected $instanceModes;
    /** @var  EntityRepository */
    protected $bosses;

    protected function startup()
    {
        parent::startup();

        $this->instances = $this->getRepository(Instance::class);
        $this->instanceTypes = $this->getRepository(InstanceType::class);
        $this->instanceModes = $this->getRepository(InstanceMode::class);
        $this->bosses = $this->getRepository(Boss::class);
    }

    public function createInstance(User $createdBy, Game $game, InstanceType $instanceType, string $name) : Instance
    {
        $instance = new Instance($createdBy);
        $instance->setGame($game);
        $instance->setInstanceType($instanceType);
        $instance->setName($name);

        $this->persist($instance);
        return $instance;
    }

    public function createInstanceMode(User $createdBy, Instance $instance, string $name, int $requiredLevel, int $minPlayers, int $maxPlayers, $apiIdentifier = null) : InstanceMode
    {
        $mode = new InstanceMode($createdBy);
        $mode->setInstance($instance);
        $mode->setName($name);
        $mode->setApiIdentifier($apiIdentifier);

        $mode->setRequiredLevel($requiredLevel);
        $mode->setRequiredPlayers($minPlayers);
        $mode->setMaximumPlayers($maxPlayers);

        $this->persist($mode);
        return $mode;
    }

    public function createInstanceType(User $createdBy, Game $game, string $name, bool $instanceType = InstanceType::PVE) : InstanceType
    {
        $type = new InstanceType($createdBy);
        $type->setName($name);
        $type->setGame($game);
        $type->setType($instanceType);

        $this->persist($type);
        return $type;
    }

    public function createBoss(User $createdBy, Instance $instance, string $name) : Boss
    {
        $boss = new Boss($createdBy);
        $boss->setInstance($instance);
        $boss->setName($name);

        $this->persist($boss);
        return $boss;
    }

    /**
     * @param int $id
     * @return null|Instance
     */
    public function findInstanceById(int $id)
    {
        return $this->instances->find($id);
    }

    /**
     * @param int $id
     * @return null|InstanceType
     */
    public function findInstanceTypeById(int $id)
    {
        return $this->instanceTypes->find($id);
    }

    public function getInstancesNameAssoc(Game $game)
    {
        return $this->instances->findAssoc(['game' => $game], 'name');
    }

    public function getInstanceTypesNameAssoc(Game $game)
    {
        return $this->instanceTypes->findAssoc(['game' => $game], 'name');
    }

    /**
     * @param Game $game
     * @return QueryBuilder
     */
    public function getInstancesGridDataSource(Game $game) : QueryBuilder
    {
        return $this->instances->createQueryBuilder('i')
            ->leftJoin(InstanceType::class, 't', Join::WITH, "t.id = i.instanceType")
            ->where('i.game = :game')->setParameter('game', $game);
    }

    /**
     * @param Game $game
     * @return QueryBuilder
     */
    public function getInstanceTypesGridDataSource(Game $game) : QueryBuilder
    {
        return $this->instanceTypes->createQueryBuilder('t')->where('t.game = :game')->setParameter('game', $game);
    }

    public function getBossesGridDataSource(Game $game) : QueryBuilder
    {
        return $this->bosses->createQueryBuilder('b')
            ->leftJoin(Instance::class, 'i', Join::WITH, "i.id = b.instance")
            ->leftJoin(InstanceType::class, 't', Join::WITH, "t.id = i.instanceType")
            ->where('i.game = :game')->setParameter('game', $game);
    }

    /**
     * @param $gameEntity
     * @return array
     */
    public function getInstanceTypeNamePairs($gameEntity) : array
    {
        return $this->instanceTypes->findPairs(['game' =>$gameEntity], 'name');
    }

}