<?php

declare(strict_types=1);

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Uid\Uuid;

#[ORM\Entity(repositoryClass: \App\Repository\ModelGenerationConfigRepository::class)]
#[ORM\Table(name: 'model_generation_config')]
#[ORM\Index(name: 'idx_model_active', columns: ['model_name', 'active'])]
class ModelGenerationConfig
{
    // -----------------------------
    // Hard Guardrails
    // -----------------------------
    private const MAX_RETRIEVAL_CHUNKS = 200;
    private const MAX_VECTOR_TOPK = 200;

    #[ORM\Id]
    #[ORM\Column(type: 'uuid', unique: true)]
    private Uuid $id;

    #[ORM\Column(name: 'model_name', type: 'string', length: 120)]
    private string $modelName;

    #[ORM\Column(type: 'boolean')]
    private bool $stream;

    #[ORM\Column(type: 'float')]
    private float $temperature;

    #[ORM\Column(name: 'top_k', type: 'integer')]
    private int $topK;

    #[ORM\Column(name: 'top_p', type: 'float')]
    private float $topP;

    #[ORM\Column(name: 'repeat_penalty', type: 'float')]
    private float $repeatPenalty;

    #[ORM\Column(name: 'num_ctx', type: 'integer')]
    private int $numCtx;

    // -------------------------------------
    // Retrieval-Parameter (NEU)
    // -------------------------------------

    #[ORM\Column(name: 'retrieval_max_chunks', type: 'integer')]
    private int $retrievalMaxChunks;

    #[ORM\Column(name: 'retrieval_vector_top_k', type: 'integer')]
    private int $retrievalVectorTopK;

    #[ORM\Column(type: 'boolean')]
    private bool $active;

    #[ORM\Column(type: 'integer')]
    private int $version;

    #[ORM\Column(name: 'created_at', type: 'datetime_immutable')]
    private \DateTimeImmutable $createdAt;

    public function __construct(
        string $modelName,
        int $version,
        bool $stream = false,
        float $temperature = 0.1,
        int $topK = 20,
        float $topP = 0.8,
        float $repeatPenalty = 1.05,
        int $numCtx = 4096,
        bool $active = false,
        int $retrievalMaxChunks = 25,
        int $retrievalVectorTopK = 25,
    ) {
        $this->id = Uuid::v4();
        $this->modelName = $modelName;
        $this->version = $version;
        $this->stream = $stream;
        $this->temperature = $temperature;
        $this->topK = $topK;
        $this->topP = $topP;
        $this->repeatPenalty = $repeatPenalty;
        $this->numCtx = $numCtx;
        $this->active = $active;
        $this->createdAt = new \DateTimeImmutable();

        $this->setRetrievalMaxChunks($retrievalMaxChunks);
        $this->setRetrievalVectorTopK($retrievalVectorTopK);
    }

    // -----------------------------
    // Getter
    // -----------------------------

    public function getId(): Uuid { return $this->id; }
    public function getModelName(): string { return $this->modelName; }
    public function isStream(): bool { return $this->stream; }
    public function getTemperature(): float { return $this->temperature; }
    public function getTopK(): int { return $this->topK; }
    public function getTopP(): float { return $this->topP; }
    public function getRepeatPenalty(): float { return $this->repeatPenalty; }
    public function getNumCtx(): int { return $this->numCtx; }
    public function isActive(): bool { return $this->active; }
    public function getVersion(): int { return $this->version; }
    public function getCreatedAt(): \DateTimeImmutable { return $this->createdAt; }

    public function getRetrievalMaxChunks(): int
    {
        return $this->retrievalMaxChunks;
    }

    public function getRetrievalVectorTopK(): int
    {
        return $this->retrievalVectorTopK;
    }

    // -----------------------------
    // Controlled Mutators
    // -----------------------------

    // Nur vom Manager nutzen
    public function setActive(bool $active): void
    {
        $this->active = $active;
    }

    public function setRetrievalMaxChunks(int $value): void
    {
        $value = max(1, min($value, self::MAX_RETRIEVAL_CHUNKS));
        $this->retrievalMaxChunks = $value;
    }

    public function setRetrievalVectorTopK(int $value): void
    {
        $value = max(1, min($value, self::MAX_VECTOR_TOPK));
        $this->retrievalVectorTopK = $value;
    }
}