<?php

declare(strict_types=1);

namespace App\Infrastructure\AI;

use App\Domain\AI\AiModel;
use App\Domain\AI\AiProvider;
use App\Domain\AI\AiQuery;
use App\Domain\AI\AiResponse;
use App\Domain\AI\Exception\AiProviderUnavailableException;

final readonly class AiService
{
    public function __construct(
        private AiHandlerFactory $handlerFactory
    ) {
    }

    public function query(
        string $message,
        AiModel $model = AiModel::GPT_35_TURBO,
        array $messages = [],
        float $temperature = 0.7,
        ?int $maxTokens = null
    ): AiResponse {
        $query = new AiQuery($message, $model, $messages, $temperature, $maxTokens);
        $handler = $this->handlerFactory->createForModel($model);

        return $handler($query);
    }

    public function queryWithFallback(
        string $message,
        AiModel $preferredModel = AiModel::GPT_35_TURBO,
        array $messages = [],
        float $temperature = 0.7,
        ?int $maxTokens = null
    ): AiResponse {
        // Zuerst bevorzugtes Modell versuchen
        try {
            return $this->query($message, $preferredModel, $messages, $temperature, $maxTokens);
        } catch (AiProviderUnavailableException $e) {
            // Fallback auf verfügbare Modelle
            $availableModels = $this->handlerFactory->getAvailableModels();

            if (empty($availableModels)) {
                throw new AiProviderUnavailableException(
                    $preferredModel->getProvider(),
                    'Keine AI-Provider verfügbar. Prüfen Sie Ihre Konfiguration.'
                );
            }

            // Erstes verfügbares Modell verwenden
            $fallbackModel = $availableModels[0];

            return $this->query($message, $fallbackModel, $messages, $temperature, $maxTokens);
        }
    }

    public function queryWithConversation(
        array $messages,
        AiModel $model = AiModel::GPT_35_TURBO,
        float $temperature = 0.7,
        ?int $maxTokens = null
    ): AiResponse {
        // Für Gespräche verwenden wir eine leere Nachricht, da die messages bereits alles enthalten
        $query = new AiQuery('', $model, $messages, $temperature, $maxTokens);
        $handler = $this->handlerFactory->createForModel($model);

        return $handler($query);
    }

    public function getAvailableProviders(): array
    {
        return $this->handlerFactory->getAvailableProviders();
    }

    public function getAvailableModels(): array
    {
        return $this->handlerFactory->getAvailableModels();
    }

    public function isProviderAvailable(AiProvider $provider): bool
    {
        return $this->handlerFactory->isProviderAvailable($provider);
    }

    public function getOllamaAvailableModels(): array
    {
        return $this->handlerFactory->getOllamaAvailableModels();
    }
}
