<?php

declare(strict_types=1);

namespace App\Service\Admin;

use App\Entity\Document;
use App\Entity\Tag;
use App\Service\TagRebuildJobService;
use App\Tag\TagService;
use App\Tag\TagTypes;
use Doctrine\ORM\EntityManagerInterface;
use RuntimeException;

final readonly class DocumentTagAdminService
{
    public function __construct(
        private EntityManagerInterface $em,
        private TagService $tagService,
        private TagRebuildJobService $jobs,
    ) {
    }

    /**
     * @return array{
     *   document: Document,
     *   allTags: list<Tag>,
     *   latestJob: mixed,
     *   hasActiveJob: bool
     * }
     */
    public function getEditData(string $documentId): array
    {
        $document = $this->findDocumentById($documentId);

        /** @var list<Tag> $allTags */
        $allTags = $this->em->getRepository(Tag::class)->findAll();

        usort(
            $allTags,
            static function (Tag $left, Tag $right): int {
                $typeOrder = [
                    TagTypes::CATALOG_ENTITY => 10,
                    TagTypes::GENERIC => 20,
                    TagTypes::SALES_SIGNAL => 30,
                ];

                $leftTypeRank = $typeOrder[$left->getType()] ?? 999;
                $rightTypeRank = $typeOrder[$right->getType()] ?? 999;

                if ($leftTypeRank !== $rightTypeRank) {
                    return $leftTypeRank <=> $rightTypeRank;
                }

                $labelComparison = strcasecmp($left->getLabel(), $right->getLabel());

                if ($labelComparison !== 0) {
                    return $labelComparison;
                }

                return strcmp($left->getSlug(), $right->getSlug());
            }
        );

        return [
            'document' => $document,
            'allTags' => $allTags,
            'latestJob' => $this->jobs->getLatestJob(),
            'hasActiveJob' => $this->jobs->hasActiveJob(),
        ];
    }

    /**
     * Persists the selected tag set for a document via the central domain service.
     *
     * @param array<mixed> $selectedTagIds
     */
    public function saveTags(string $documentId, array $selectedTagIds): void
    {
        $document = $this->findDocumentById($documentId);

        $this->tagService->syncDocumentTags($document, $selectedTagIds);
    }

    public function getLatestRebuildStatus(): ?string
    {
        return $this->jobs->getLatestJob()?->getStatus();
    }

    private function findDocumentById(string $documentId): Document
    {
        $documentId = trim($documentId);

        if ($documentId === '') {
            throw new RuntimeException('Document not found.');
        }

        $document = $this->em->getRepository(Document::class)->find($documentId);

        if (!$document instanceof Document) {
            throw new RuntimeException('Document not found.');
        }

        return $document;
    }
}