<?php

namespace App\Domain\Manga\Infrastructure\Persistence\Repository;

use App\Domain\Manga\Domain\Contract\Repository\ChapterRepositoryInterface;
use App\Domain\Manga\Domain\Model\Chapter;
use App\Domain\Manga\Domain\Model\ValueObject\ChapterId;
use App\Entity\Chapter as ChapterEntity;
use Doctrine\ORM\EntityManagerInterface;

readonly class LegacyChapterRepository implements ChapterRepositoryInterface
{
    public function __construct(
        private EntityManagerInterface $entityManager
    ) {}

    public function findById(string $id): ?Chapter
    {
        $entity = $this->entityManager->find(ChapterEntity::class, $id);

        return $entity ? $this->toDomainModel($entity) : null;
    }

    public function findVisibleById(string $id): ?Chapter
    {
        $qb = $this->entityManager->createQueryBuilder()
            ->select('c')
            ->from(ChapterEntity::class, 'c')
            ->where('c.id = :id')
            ->andWhere('c.visible = :visible')
            ->setParameter('id', $id)
            ->setParameter('visible', 1);

        $entity = $qb->getQuery()->getOneOrNullResult();

        return $entity ? $this->toDomainModel($entity) : null;
    }

    public function findByMangaIdAndChapterNumber(string $mangaId, float $chapterNumber): ?Chapter
    {
        $qb = $this->entityManager->createQueryBuilder()
            ->select('c')
            ->from(ChapterEntity::class, 'c')
            ->where('c.manga = :mangaId')
            ->andWhere('c.number = :chapterNumber')
            ->setParameter('mangaId', $mangaId)
            ->setParameter('chapterNumber', $chapterNumber);

        $entity = $qb->getQuery()->getOneOrNullResult();

        return $entity ? $this->toDomainModel($entity) : null;
    }

    public function save(Chapter $chapter): void
    {
        $entity = $this->entityManager->find(ChapterEntity::class, $chapter->getId());

        if (!$entity) {
            throw new \RuntimeException(sprintf('Chapter with id %s not found', $chapter->getId()));
        }

        $entity->setVisible($chapter->isVisible());
        $entity->setCbzPath($chapter->getCbzPath());
        $entity->setTitle($chapter->getTitle());
        $entity->setVolume($chapter->getVolume());

        $this->entityManager->persist($entity);
        $this->entityManager->flush();
    }

    public function delete(Chapter $chapter): void
    {
        $entity = $this->entityManager->find(ChapterEntity::class, $chapter->getId());

        if ($entity) {
            $this->entityManager->remove($entity);
            $this->entityManager->flush();
        }
    }

    public function findByMangaIdAndVolume(string $mangaId, int $volume): array
    {
        $entities = $this->entityManager->getRepository(ChapterEntity::class)
            ->findBy(['manga' => $mangaId, 'volume' => $volume]);

        return array_map([$this, 'toDomainModel'], $entities);
    }

    public function findVisibleByMangaIdAndVolume(string $mangaId, int $volume): array
    {
        $entities = $this->entityManager->getRepository(ChapterEntity::class)
            ->findBy(['manga' => $mangaId, 'volume' => $volume, 'visible' => true]);

        return array_map([$this, 'toDomainModel'], $entities);
    }

    public function findVisibleWithCbzByMangaIdAndVolume(string $mangaId, int $volume): array
    {
        $qb = $this->entityManager->createQueryBuilder()
            ->select('c')
            ->from(ChapterEntity::class, 'c')
            ->where('c.manga = :mangaId')
            ->andWhere('c.volume = :volume')
            ->andWhere('c.visible = true')
            ->andWhere('c.cbzPath IS NOT NULL')
            ->setParameter('mangaId', $mangaId)
            ->setParameter('volume', $volume)
            ->orderBy('c.number', 'ASC');

        $entities = $qb->getQuery()->getResult();

        return array_map([$this, 'toDomainModel'], $entities);
    }

    private function toDomainModel(ChapterEntity $entity): Chapter
    {
        return new Chapter(
            new ChapterId((string) $entity->getId()),
            (string) $entity->getManga()->getId(),
            $entity->getNumber(),
            $entity->getTitle(),
            $entity->getVolume(),
            $entity->isVisible(),
            $entity->getCbzPath(),
            new \DateTimeImmutable()
        );
    }
}
