<?php

namespace App\Service\SnipContent;

use App\Entity\Snip;
use App\Entity\SnipContent;
use Doctrine\ORM\EntityManagerInterface;

readonly class SnipContentService
{

    public function __construct(
        private EntityManagerInterface $em,
    ) {}

    public function update(Snip $snip, string $contents, ?string $contentName): void
    {
        $parentContent = $snip->getActiveVersion();
        if (self::rebuildText($parentContent) === $contents) {
            return;
        }

        // Create new snipContent entity with previous one as parent
        $content = new SnipContent();
        $content
            ->setText($contents)
            ->setSnip($snip)
            ->setName($contentName)
        ;
        if ($parentContent !== null) {
            $content->setParent($parentContent);
            $this->contentToRelative($parentContent);
        }

        $this->em->persist($content);
        $this->em->flush();

        $snip->setActiveVersion($content);
        $this->em->persist($snip);
        $this->em->flush();
    }

    public static function rebuildText(?SnipContent $snipContent): string
    {
        if ($snipContent === null) {
            return '';
        }
        if ($snipContent->getText()) {
            return $snipContent->getText();
        }

        $parentContent = $snipContent->getParent();
        if ($parentContent === null && $snipContent->getDiff() === null) {
            return '---Something went very wrong, cant rebuild the text---';
        }

        return MyersDiff::rebuildBFromCompact(
            self::rebuildText($parentContent), $snipContent->getDiff()
        );
    }

    public function setVersion(Snip $snip, SnipContent $version): void
    {
        $activeVersion = $snip->getActiveVersion();
        $this->contentToAbsolute($version);
        $this->contentToRelative($activeVersion);

        $snip->setActiveVersion($version);
        $this->em->persist($snip);
        $this->em->flush();
    }

    public function contentToRelative(SnipContent $content): void
    {
        if ($content->getText() === null || $content->getParent() === null) {
            return;
        }
        $contentText = $content->getText();
        $parentText = self::rebuildText($content->getParent());
        $diff = MyersDiff::calculate($parentText, $contentText);
        $content->setDiff($diff);
        $content->setText(null);
        $this->em->persist($content);
        $this->em->flush();
    }

    public function contentToAbsolute(SnipContent $content): void
    {
        if ($content->getDiff() === null) {
            return;
        }
        $content->setText(self::rebuildText($content));
        $content->setDiff(null);
        $this->em->persist($content);
        $this->em->flush();
    }
}