<?php


namespace App\Model\Facades\Writers;


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\Facades\Readers\GameReader;
use App\Model\Facades\Readers\InstanceReader;
use App\Model\Services\InstanceService;
use Throwable;

class InstanceWriter extends BaseWriter
{
    /** @var  GameReader */
    protected $gameReader;
    /** @var  InstanceService */
    protected $instanceService;
    /** @var  InstanceReader */
    protected $instanceReader;

    public function inject(GameReader $gameReader, InstanceService $instanceService, InstanceReader $instanceReader)
    {
        $this->gameReader = $gameReader;
        $this->instanceService = $instanceService;
        $this->instanceReader = $instanceReader;
    }

    /**
     * @param $game
     * @param int|InstanceType $instanceType
     * @param string $name
     * @return Instance
     * @throws Throwable
     */
    public function createInstance($game, $instanceType, string $name) : Instance
    {
        $gameEntity = $this->gameReader->validateGame($game);
        $instanceTypeEntity = $this->instanceReader->validateInstanceType($instanceType);

        try {
            $this->beginTransaction();
            $instance = $this->instanceService->createInstance($this->getLoggedInUser(), $gameEntity, $instanceTypeEntity, $name);
            $this->commit();
        } catch (Throwable $e) {
            $this->rollback();
            throw $e;
        }

        return $instance;
    }

    public function createInstanceType($game, string $name, bool $instanceType = InstanceType::PVE) : InstanceType
    {
        $gameEntity = $this->gameReader->validateGame($game);

        try {
            $this->beginTransaction();
            $instanceType = $this->instanceService->createInstanceType($this->getLoggedInUser(), $gameEntity, $name, $instanceType);
            $this->commit();
        } catch (Throwable $e) {
            $this->rollback();
            throw $e;
        }

        return $instanceType;
    }

    public function createInstanceMode($instance, string $name, int $requiredLevel, int $minPlayers, int $maxPlayers, $apiIdentifier = null) : InstanceMode
    {
        $instanceEntity = $this->instanceReader->validateInstance($instance);

        try {
            $this->beginTransaction();
            $instanceMode = $this->instanceService->createInstanceMode($this->getLoggedInUser(), $instanceEntity, $name, $requiredLevel, $minPlayers, $maxPlayers, $apiIdentifier);
            $this->commit();
        } catch (Throwable $e) {
            $this->rollback();
            throw $e;
        }

        return $instanceMode;
    }

    public function createBoss($instance, string $name) : Boss
    {
        $instanceEntity = $this->instanceReader->validateInstance($instance);

        try {
            $this->beginTransaction();
            $boss = $this->instanceService->createBoss($this->getLoggedInUser(), $instanceEntity, $name);
            $this->commit();
        } catch (Throwable $e) {
            $this->rollback();
            throw $e;
        }

        return $boss;
    }

    public function editInstanceTypeName($instanceType, string $newName)
    {
        $instanceTypeEntity = $this->instanceReader->validateInstanceType($instanceType);

        try {
            $this->beginTransaction();
            $instanceTypeEntity->setName($newName);
            $instanceTypeEntity->setEditedBy($this->getLoggedInUser());
            $this->commit();
        } catch (Throwable $e) {
            $this->rollback();
            throw $e;
        }
    }

    public function editInstanceName($instance, $newName)
    {
        $instanceEntity = $this->instanceReader->validateInstance($instance);

        try {
            $this->beginTransaction();
            $instanceEntity->setName($newName);
            $instanceEntity->setEditedBy($this->getLoggedInUser());
            $this->commit();
        } catch (Throwable $e) {
            $this->rollback();
            throw $e;
        }
    }
}