<?php

declare(strict_types=1);

namespace App\Knowledge\Ingest;

use App\Entity\DocumentVersion;
use App\Knowledge\Text\TextNormalizer;
use App\Repository\DocumentVersionRepository;
use App\Ingest\DocumentSanitizer;
use App\Ingest\StructureEnhancer;

final readonly class KnowledgeIngestService
{
    public function __construct(
        private DocumentLoader            $loader,
        private SimpleChunker             $chunker,
        private DocumentVersionRepository $versionRepo,
        private TextNormalizer            $textNormalizer,
        private DocumentSanitizer         $documentSanitizer,
        private StructureEnhancer         $structureEnhancer,
    ) {}

    /**
     * Lokaler Ingest: erzeugt deterministische NDJSON-Records.
     *
     * @return iterable<array<string,mixed>>
     */
    public function buildChunkRecords(DocumentVersion $version): iterable
    {
        // 1️⃣ Rohtext laden
        $text = $this->loader->load($version->getFilePath());
        $extension = $version->getFileExtension() ?? 'txt';

        // 2️⃣ Artefakt-Sanitizing
        $text = $this->documentSanitizer->sanitize($text, $extension);

        // 3️⃣ Struktur-Hints (deterministisch, minimal)
        $text = $this->structureEnhancer->enhance($text);

        // 4️⃣ Chunking (inkl. TextNormalizer)
        $chunks = $this->chunker->chunk($text);

        $doc = $version->getDocument();
        $documentId = $doc->getId()->toRfc4122();
        $versionId  = $version->getId()->toRfc4122();

        $title = trim((string)$doc->getTitle());

        $index = 0;

        foreach ($chunks as $chunkText) {

            // 🔥 Titel nur im ersten Chunk einfügen
            if ($title && $title !== '') {
                $chunkText = "# Produkt Titel: `" . $title . "`\n\n" . $chunkText;
            }

            $chunkText = trim($chunkText);

            // 🔥 Deterministische Chunk-ID
            // Wichtig: Normalisierung NUR für ID-Bildung
            $normalizedForId = $this->textNormalizer->normalize($chunkText);

            $chunkId = sha1(
                $documentId . '|' .
                $versionId  . '|' .
                $normalizedForId
            );

            yield [
                'chunk_id'    => $chunkId,
                'document_id' => $documentId,
                'version_id'  => $versionId,
                'chunk_index' => $index,
                'text'        => $chunkText,
                'checksum'    => sha1($chunkText),
                'metadata'    => $this->buildMetadata($version),
            ];

            $index++;
        }
    }

    /**
     * Global Reindex
     */
    public function buildAllActiveChunkRecords(): iterable
    {
        foreach ($this->versionRepo->iterateActiveVersions() as $version) {
            yield from $this->buildChunkRecords($version);
        }
    }

    /**
     * @return array<string,mixed>
     */
    private function buildMetadata(DocumentVersion $version): array
    {
        $doc = $version->getDocument();

        $title = null;

        if (method_exists($doc, 'getTitle')) {
            $title = $doc->getTitle();
        } elseif (method_exists($doc, 'getName')) {
            $title = $doc->getName();
        }

        return array_filter([
            'document_title' => $title,
            'version_number' => method_exists($version, 'getVersionNumber')
                ? $version->getVersionNumber()
                : null,
            'file_path' => $version->getFilePath(),
        ], static fn($v) => $v !== null && $v !== '');
    }
}