<?php

namespace Snaju\Inception\ORM;

use Composer\Cache;
use Doctrine\Common\Cache\CacheProvider;
use Doctrine\Common\Cache\FilesystemCache;
use Doctrine\Common\Cache\Psr6\DoctrineProvider;
use Doctrine\Common\Cache\RedisCache;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\Configuration;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\ORMSetup;
use Doctrine\ORM\Tools\SchemaTool;
use Doctrine\ORM\Tools\Setup;
use Snaju\Inception\InceptionCore;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;

class ORM
{
    /**
     * @var EntityManager
     */
    public static $EntityManager;

    /**
     * @var array
     */
    private static $modelLocations = [];
    /**
     * @var bool
     */
    private static $devMode = false;
    /**
     * @var bool
     */
    private static $generateSchema = false;

    public static ?\Doctrine\Common\Cache\Cache $cache = null;

    /**
     * @return \Doctrine\ORM\Configuration
     */
    public static function init(): Configuration
    {

        Type::addType("uuid", 'Ramsey\Uuid\Doctrine\UuidType');
        Type::addType("magicid", "\Snaju\Inception\ORM\MagicIdType");

//        $cache = null;
//
//        if (extension_loaded('redis')) {
//            try {
//                $redis = new \Redis();
//                $redis->connect('localhost', 6379);
//
//                if ($redis->isConnected()) {
//                    $cache = new RedisCache();
//                    $cache->setRedis($redis);
//                }
//            } catch (\RedisException $e) {
//                // Fall back to other db usage.
//            }
//        }
//
//        self::$cache = $cache;

        $cachePool = new FilesystemAdapter('', 0, InceptionCore::getBase() . "/tmp/orm");
//        self::$cache = $cache;

        if(env("DB_META") == "attr") {
            return ORMSetup::createAttributeMetadataConfiguration(self::$modelLocations, self::$devMode, null, $cachePool);
        } else {
            return ORMSetup::createAnnotationMetadataConfiguration(self::$modelLocations, self::$devMode, null, $cachePool);
        }

//        return Setup::createAnnotationMetadataConfiguration(self::$modelLocations, self::$devMode, null, self::$cache, false);
    }

    public static function getClasses()
    {
        $models = [];
        $classes = self::$EntityManager->getMetadataFactory()->getAllMetadata();
        foreach ($classes as $class) {
            if ($class instanceof ClassMetadata) {
                $models[] = new $class->name();
            }
        }

        return $models;
    }

    public static function flush($objs = [])
    {
        if (count($objs) == 0) {
            self::$EntityManager->flush();

        } else {
            self::$EntityManager->flush($objs);
        }
    }

    public static function connect(array $connection, Configuration $configuration): EntityManager
    {
        self::$EntityManager = EntityManager::create($connection, $configuration);
        return self::$EntityManager;
    }

    public static function createSchema()
    {
        if (self::isAlive()) {
            $tool = new SchemaTool(self::$EntityManager);
            $classes = self::$EntityManager->getMetadataFactory()->getAllMetadata();
            $tool->createSchema($classes);
        } else {
            throw new \Exception("EntityManager not set, cannot make schema");
        }
    }

    public static function updateSchema()
    {
        if (self::isAlive()) {
            $tool = new SchemaTool(self::$EntityManager);
            $classes = self::$EntityManager->getMetadataFactory()->getAllMetadata();
            $tool->updateSchema($classes);
        } else {
            throw new \Exception("EntityManager not set, cannot update schema");
        }
    }

    public static function isAlive()
    {
        return (self::$EntityManager != null && self::$EntityManager instanceof EntityManager);
    }

    /**
     * @param $dir
     */
    public static function addModelLocation($dir)
    {
        self::$modelLocations[] = $dir;
    }

    /**
     * @return mixed
     */
    public static function getEntityManager()
    {
        return self::$EntityManager;
    }

    /**
     * @param mixed $EntityManager
     */
    public static function setEntityManager($EntityManager)
    {
        self::$EntityManager = $EntityManager;
    }

    /**
     * @return array
     */
    public static function getModelLocations(): array
    {
        return self::$modelLocations;
    }

    /**
     * @param array $modelLocations
     */
    public static function setModelLocations(array $modelLocations)
    {
        self::$modelLocations = $modelLocations;
    }

    /**
     * @return bool
     */
    public static function isDevMode(): bool
    {
        return self::$devMode;
    }

    /**
     * @param bool $devMode
     */
    public static function setDevMode(bool $devMode)
    {
        self::$devMode = $devMode;
    }

    /**
     * @return bool
     */
    public static function isGenerateSchema(): bool
    {
        return self::$generateSchema;
    }

    /**
     * @param bool $generateSchema
     */
    public static function setGenerateSchema(bool $generateSchema)
    {
        self::$generateSchema = $generateSchema;
    }

    public static function getDataModelFromMagicId(string $magicId)
    {
        $a = json_decode(base64_decode($magicId), true);
        $className = $a['c'];
        $uuid = $a['id'];

        if (class_exists($className)) {
            $obj = new $className();
            if ($obj instanceof DataModel) {
                return $obj::get($uuid);
            }
        }

        return null;
    }
}

?>