<?php

declare(strict_types=1);

namespace ImovelZapAi\AiGateway\Infrastructure\Providers;

use Illuminate\Support\ServiceProvider;
use ImovelZapAi\AiGateway\Application\Queries\GetAiGatewayUsageQuery;
use ImovelZapAi\AiGateway\Application\Services\AiCostCalculator;
use ImovelZapAi\AiGateway\Application\Services\AiGateway;
use ImovelZapAi\AiGateway\Application\Services\AiQuotaGuard;
use ImovelZapAi\AiGateway\Application\Services\AiRequestLogger;
use ImovelZapAi\AiGateway\Application\Services\AiRetryPolicy;
use ImovelZapAi\AiGateway\Infrastructure\Services\AiProviderResolver;

class AiGatewayServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->mergeConfigFrom(config_path('ai_gateway.php'), 'ai_gateway');

        $this->app->singleton(OpenAiProvider::class, function (): OpenAiProvider {
            $config = config('ai_gateway.providers.openai', []);

            return new OpenAiProvider(
                apiKey: is_string($config['api_key'] ?? null) ? $config['api_key'] : null,
                baseUrl: (string) ($config['base_url'] ?? 'https://api.openai.com/v1'),
                timeoutSeconds: (int) ($config['timeout_seconds'] ?? 60),
            );
        });

        $this->app->singleton(NullAiProvider::class);

        $this->app->singleton(AiProviderResolver::class, function ($app): AiProviderResolver {
            return new AiProviderResolver(
                openAi: $app->make(OpenAiProvider::class),
                null: $app->make(NullAiProvider::class),
                defaultProvider: (string) config('ai_gateway.default_provider', 'null'),
            );
        });

        $this->app->singleton(AiCostCalculator::class, function (): AiCostCalculator {
            /** @var array<string, array{input: float, output: float}> $pricing */
            $pricing = config('ai_gateway.pricing', []);

            return new AiCostCalculator($pricing);
        });

        $this->app->singleton(AiQuotaGuard::class, function (): AiQuotaGuard {
            return new AiQuotaGuard(
                dailyTokenLimit: (int) config('ai_gateway.quotas.daily_tokens_per_tenant', 0),
                monthlyCostLimitUsd: (float) config('ai_gateway.quotas.monthly_cost_usd_per_tenant', 0),
            );
        });

        $this->app->singleton(AiRetryPolicy::class, function (): AiRetryPolicy {
            return new AiRetryPolicy(
                maxAttempts: (int) config('ai_gateway.retry.max_attempts', 3),
                baseDelayMs: (int) config('ai_gateway.retry.base_delay_ms', 500),
                maxDelayMs: (int) config('ai_gateway.retry.max_delay_ms', 5000),
            );
        });

        $this->app->singleton(AiRequestLogger::class);

        $this->app->singleton(GetAiGatewayUsageQuery::class);

        $this->app->singleton(AiGateway::class, function ($app): AiGateway {
            $openAiConfig = config('ai_gateway.providers.openai', []);

            return new AiGateway(
                enabled: (bool) config('ai_gateway.enabled', false),
                providerResolver: $app->make(AiProviderResolver::class),
                quotaGuard: $app->make(AiQuotaGuard::class),
                retryPolicy: $app->make(AiRetryPolicy::class),
                costCalculator: $app->make(AiCostCalculator::class),
                requestLogger: $app->make(AiRequestLogger::class),
                defaultModel: (string) ($openAiConfig['default_model'] ?? 'gpt-4.1-nano'),
            );
        });
    }

    public function boot(): void
    {
        if ($this->app->runningInConsole()) {
            $this->commands([
                \ImovelZapAi\AiGateway\Infrastructure\Console\PingOpenAiCommand::class,
            ]);
        }
    }
}
