<?php

namespace App\Services;

use App\Models\HomepageLead;
use App\Models\SystemSetting;
use App\Services\AI\Providers\AnthropicProvider;
use App\Services\AI\Providers\GeminiProvider;
use App\Services\AI\Providers\MistralProvider;
use App\Services\AI\Providers\OpenAIProvider;
use App\Services\AI\Providers\ProviderResponse;

/**
 * Self-contained AI bridge for the homepage agent. Reads admin-level API
 * keys from the AI Providers panel (system_settings) and calls the matching
 * provider directly — no workspace, no AiConfig, no shortcuts. Returns the
 * raw reply plus accounting metadata so the lead row can track cost.
 */
class HomepageAgentService
{
    /** Default models per provider when admin has not picked one. */
    private const FALLBACK_MODELS = [
        'openai'    => 'gpt-4o-mini',
        'anthropic' => 'claude-haiku-4-5-20251001',
        'gemini'    => 'gemini-2.0-flash',
        'mistral'   => 'mistral-small-latest',
    ];

    public function isReady(): bool
    {
        $provider = $this->resolveProviderKey();
        $apiKey   = $this->apiKeyFor($provider);
        return $provider !== '' && $apiKey !== '';
    }

    public function status(): array
    {
        $provider = $this->resolveProviderKey();
        $hasKey   = $provider !== '' && $this->apiKeyFor($provider) !== '';
        return [
            'ready'    => $hasKey,
            'provider' => $provider,
            'model'    => $this->modelFor($provider),
        ];
    }

    /**
     * Send a single visitor message to the configured AI and return the reply
     * plus the cost metadata. The caller is responsible for persisting both
     * sides of the exchange onto the HomepageLead.
     */
    public function generateReply(string $userMessage, HomepageLead $lead): array
    {
        $providerKey = $this->resolveProviderKey();
        $apiKey      = $this->apiKeyFor($providerKey);

        if ($providerKey === '' || $apiKey === '') {
            throw new \RuntimeException('Homepage agent: no AI provider configured.');
        }

        $provider = $this->instantiate($providerKey, $apiKey);
        $model    = $this->modelFor($providerKey);

        $systemPrompt = $this->buildSystemPrompt($lead);
        $history      = $this->buildHistory($lead);

        /** @var ProviderResponse $response */
        $response = $provider->chat($systemPrompt, $userMessage, [
            'model'                => $model,
            'temperature'          => 0.5,
            'max_reply_length'     => 'medium',
            'top_p'                => 0.9,
            'frequency_penalty'    => 0.2,
            'presence_penalty'     => 0.1,
            'conversation_history' => $history,
        ]);

        return [
            'content'       => trim((string) ($response->content ?? '')),
            'provider'      => $providerKey,
            'model'         => $model,
            'tokens_in'     => (int) ($response->tokens_in ?? 0),
            'tokens_out'    => (int) ($response->tokens_out ?? 0),
            'cost'          => (float) ($response->cost ?? 0),
        ];
    }

    private function resolveProviderKey(): string
    {
        $provider = strtolower(trim((string) SystemSetting::get('ai_default_provider', 'openai')));
        return in_array($provider, ['openai', 'anthropic', 'gemini', 'mistral'], true) ? $provider : 'openai';
    }

    private function apiKeyFor(string $providerKey): string
    {
        $map = [
            'openai'    => 'openai_api_key',
            'anthropic' => 'anthropic_api_key',
            'gemini'    => 'gemini_api_key',
            'mistral'   => 'mistral_api_key',
        ];

        $settingKey = $map[$providerKey] ?? null;
        if (! $settingKey) return '';

        return trim((string) SystemSetting::get($settingKey, ''));
    }

    private function modelFor(string $providerKey): string
    {
        $model = trim((string) SystemSetting::get('ai_default_model', ''));
        if ($model !== '') return $model;
        return self::FALLBACK_MODELS[$providerKey] ?? 'gpt-4o-mini';
    }

    private function instantiate(string $providerKey, string $apiKey): OpenAIProvider|AnthropicProvider|GeminiProvider|MistralProvider
    {
        return match ($providerKey) {
            'openai'    => new OpenAIProvider($apiKey, null),
            'anthropic' => new AnthropicProvider($apiKey),
            'gemini'    => new GeminiProvider($apiKey),
            'mistral'   => new MistralProvider($apiKey),
            default     => throw new \RuntimeException("Unsupported AI provider: {$providerKey}"),
        };
    }

    private function buildSystemPrompt(HomepageLead $lead): string
    {
        $brand      = config('app.name', 'our platform');
        $agentName  = SystemSetting::get('agent_homepage_name', 'Alex');
        $businessCtx = trim((string) SystemSetting::get('agent_homepage_business_context', ''));

        $visitorBlock = collect([
            'name'     => $lead->name,
            'email'    => $lead->email,
            'company'  => $lead->company,
            'use_case' => $lead->use_case,
            'page'     => $lead->page_url,
        ])->filter(fn ($v) => ! empty($v))
          ->map(fn ($v, $k) => "- {$k}: {$v}")
          ->implode("\n");

        $core = <<<PROMPT
You are {$agentName}, the AI sales & support assistant for {$brand}. You are chatting with a visitor on the public homepage.

YOUR ROLE:
- Greet warmly, listen, and help the visitor understand whether {$brand} fits their needs.
- Answer product questions concisely and accurately. If you don't know an answer, say so plainly and offer to have a human follow up by email.
- Qualify the lead: subtly draw out their use case, team size, timeline, and budget when relevant — without interrogating.
- When the visitor signals strong intent (asking for pricing details, a demo, or implementation help), encourage them to share their work email and what they'd like to discuss, then promise a fast follow-up.
- Never invent prices, SLAs, integrations, or features that aren't real.

STYLE:
- Friendly, professional, plain language. No corporate fluff.
- Short paragraphs. Use line breaks liberally so the chat is easy to scan on mobile.
- Match the visitor's energy — casual if they're casual, formal if they're formal.

VISITOR PROFILE (from intro form):
{$visitorBlock}
PROMPT;

        if ($businessCtx !== '') {
            $core .= "\n\nABOUT {$brand} (admin-supplied context — use this to answer accurately):\n{$businessCtx}";
        }

        return $core;
    }

    /**
     * Convert the lead's transcript into the role/content pairs the provider
     * expects as prior history. Excludes the current incoming message (the
     * caller passes that separately).
     */
    private function buildHistory(HomepageLead $lead): array
    {
        $transcript = $lead->transcript ?? [];
        $history = [];

        foreach ($transcript as $entry) {
            $role    = ($entry['role'] ?? '') === 'user' ? 'user' : 'assistant';
            $content = trim((string) ($entry['content'] ?? ''));
            if ($content === '') continue;
            $history[] = ['role' => $role, 'content' => $content];
        }

        // Cap history at the last 20 turns to keep prompts compact + costs predictable
        return array_slice($history, -20);
    }
}
