<?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->activeVersion;
        if (self::rebuildText($parentContent) === $contents) {
            return;
        }

        // Create new snipContent entity with previous one as parent
        $content = new SnipContent();
        $content->text = $contents;
        $content->snip = $snip;
        $content->name = $contentName;

        if ($parentContent !== null) {
            $content->parent = $parentContent;
            $this->contentToRelative($parentContent);
        }

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

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

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

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

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

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

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

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

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