<?php

declare(strict_types=1);

namespace App\Service\Admin;

use App\Entity\IngestProfile;
use App\Index\IndexConfigurationProvider;
use App\Index\IndexMetaManager;
use App\Index\IndexStructureComparator;
use App\Repository\IngestProfileRepository;
use Doctrine\ORM\EntityManagerInterface;

final readonly class IngestProfileAdminService
{
    public function __construct(
        private IngestProfileRepository    $repo,
        private EntityManagerInterface     $em,
        private IndexMetaManager           $metaManager,
        private IndexConfigurationProvider $provider,
        private IndexStructureComparator   $comparator,
    ) {}

    /**
     * @return array{
     *   profiles: array,
     *   activeProfile: ?IngestProfile,
     *   indexMeta: mixed,
     *   diff: array,
     *   structureMismatch: bool
     * }
     */
    public function listData(): array
    {
        $profiles = $this->repo->findBy([], ['version' => 'DESC']);
        $activeProfile = $this->repo->findActive();

        $meta = $this->metaManager->readMeta();
        $currentStructure = $this->provider->getConfiguration()->toStructureArray();

        $diff = $this->comparator->compare($meta, $currentStructure);

        $structureMismatch = false;
        foreach ($diff as $row) {
            if (!($row['equal'] ?? false)) {
                $structureMismatch = true;
                break;
            }
        }

        return [
            'profiles' => $profiles,
            'activeProfile' => $activeProfile,
            'indexMeta' => $meta,
            'diff' => $diff,
            'structureMismatch' => $structureMismatch,
        ];
    }

    /**
     * Erzeugt ein neues Profil mit nextVersion aus Repo.
     *
     * @param array{
     *   chunk_size:mixed,
     *   chunk_overlap:mixed,
     *   embedding_model:mixed,
     *   embedding_dimension:mixed,
     *   scoring_version:mixed
     * } $data
     */
    public function create(array $data): IngestProfile
    {
        $latest = $this->repo->findLatestVersion();
        $nextVersion = $latest ? $latest->getVersion() + 1 : 1;

        $chunkSize = $this->requireInt($data['chunk_size'] ?? null, 'chunk_size');
        $chunkOverlap = $this->requireInt($data['chunk_overlap'] ?? null, 'chunk_overlap');
        $embeddingModel = $this->requireString($data['embedding_model'] ?? null, 'embedding_model');
        $embeddingDim = $this->requireInt($data['embedding_dimension'] ?? null, 'embedding_dimension');
        $scoringVersion = $this->requireInt($data['scoring_version'] ?? null, 'scoring_version');

        $profile = new IngestProfile(
            $nextVersion,
            $chunkSize,
            $chunkOverlap,
            $embeddingModel,
            $embeddingDim,
            $scoringVersion
        );

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

        return $profile;
    }

    public function activate(IngestProfile $profile): void
    {
        $active = $this->repo->findActive();
        if ($active instanceof IngestProfile) {
            $active->deactivate();
        }

        $profile->activate();
        $this->em->flush();
    }

    public function remove(string $id): void
    {
        // Repo macht intern flush/remove - wie bei dir bereits
        $this->repo->remove($id);
    }

    private function requireInt(mixed $value, string $field): int
    {
        if ($value === null || $value === '') {
            throw new \InvalidArgumentException("Missing field: {$field}");
        }
        if (is_int($value)) {
            return $value;
        }
        if (is_numeric($value)) {
            return (int)$value;
        }
        throw new \InvalidArgumentException("Invalid int for {$field}");
    }

    private function requireString(mixed $value, string $field): string
    {
        if (!is_string($value) || trim($value) === '') {
            throw new \InvalidArgumentException("Invalid string for {$field}");
        }
        return trim($value);
    }
}