<?php

namespace AutoAdmin\Bundle\Admin\Helper;

use AutoAdmin\Bundle\Admin\Configuration\ConfigManager;
use AutoAdmin\Bundle\Admin\Exception\UnknownEntityException;
use AutoAdmin\Bundle\Content\Model\TranslatableInterface;
use AutoAdmin\Bundle\Core\Helper\DoctrineHelper;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Serializer\SerializerInterface;

class EntityHelper
{
    private ConfigManager $configManager;
    private EntityManagerInterface $entityManager;
    private SerializerInterface $serializer;
    public function __construct(
        ConfigManager          $configManager,
        EntityManagerInterface $entityManager,
        SerializerInterface    $serializer
    )
    {
        $this->configManager = $configManager;
        $this->entityManager = $entityManager;
        $this->serializer = $serializer;
    }

    public function findFullClassName(string $entitySlug): int|string|null
    {
        // if slug is a namespace and contains backslashes, return as is
        if (stripos($entitySlug, '\\') !== false) {
            return $entitySlug;
        }

        $entitySlug = strtolower($entitySlug);

        foreach ($this->configManager->getConfig()['entities'] as $fullClassName => $config) {
            if (!empty($config['slug']) && $config['slug'] === $entitySlug) {
                return $fullClassName;
            }
            if ($entitySlug === self::extractShortEntityName($fullClassName)) {
                return $fullClassName;
            }
        }

        return null;
    }

    public static function extractShortEntityName(string $className): string
    {
        $elements = explode('\\', $className);

        return strtolower(end($elements));
    }

    public function getEntityConfig($className)
    {
        return $this->configManager->getEntityConfigByClass($className);
    }

    public function getEntitySlugFromClass($fqdn)
    {
        $config = $this->configManager->getEntityConfigByClass($fqdn);

        return $config['slug'];
    }

    public function getEntityClassFromSlug($slug)
    {
        $config = $this->configManager->getEntityConfigBySlug($slug);

        return $config['class'];
    }

    public function getManager(): EntityManagerInterface
    {
        return $this->entityManager;
    }

    public function getSerializer(): SerializerInterface
    {
        return $this->serializer;
    }

    public function getEntityNameFromSlug($slug)
    {
        $config = $this->configManager->getEntityConfigBySlug($slug);

        return $config['name'];
    }

    public function getEntityNameFromFqdn($fqdn)
    {
        $config = $this->configManager->getEntityConfigByClass($fqdn);

        return $config['name'];
    }

    public function guessFqcn($entity)
    {
        if (is_object($entity)) {
            $class = get_class($entity);
            $class = DoctrineHelper::removeProxyPrefix($class);
            if ($metadata = $this->entityManager->getClassMetadata($class)) {
                $class = $metadata->getName();
            }
        } elseif (is_string($entity) && stripos($entity, '\\') === false) {
            $class = $this->getEntityClassFromSlug($entity);
        } elseif (is_string($entity) && class_exists($entity)) {
            $class = $entity;
        } else {
            throw new UnknownEntityException($entity);
        }

        return $class;
    }

    public function getPreviousEntity($entity)
    {
        return $this->getNearbyEntity($entity, 'previous');
    }

    public function getNextEntity($entity)
    {
        return $this->getNearbyEntity($entity, 'next');
    }

    public function getNearbyEntity($entity, $direction)
    {
        $class = get_class($entity);
        $class = DoctrineHelper::removeProxyPrefix($class);
        if ($metadata = $this->entityManager->getClassMetadata($class)) {
            $class = $metadata->getName();
        }

        $repository = $this->entityManager->getRepository($class);

        $qb = $repository->createContentQueryBuilder('e');
        $qb->andWhere('e.id ' . ($direction === 'next' ? '>' : '<') . ' :id');
        $qb->setParameter('id', $entity->getId());
        $qb->orderBy('e.id', $direction === 'next' ? 'ASC' : 'DESC');
        $qb->setMaxResults(1);

        return $qb->getQuery()->getOneOrNullResult();
    }
}
