<?php

namespace App\Services;

use App\Models\AiProvider;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Str;

class AiService
{
    protected $provider;

    public function __construct()
    {
        $this->provider = AiProvider::where('is_active', true)->where('is_enabled', true)->first();
    }

    /**
     * Rewrite content using the active AI provider.
     */
    public function rewrite(string $content, ?string $customPrompt = null)
    {
        // If Admin hasn't turned on any AI provider
        if (!$this->provider) {
            throw new \Exception("AI Rewrite is currently disabled or no active provider is configured by the Administrator.");
        }

        try {
            $apiKey = $this->getDecryptedKey($this->provider->api_key);
            
            if (empty($apiKey)) {
                throw new \Exception("The API Key is empty or missing."); 
            }

            $model = $this->provider->default_model;

            // --- 1. BUILD THE PROMPT DYNAMICALLY ---
            // We combine the base rules, the user's custom prompt, and the mandatory JSON rules.
            $systemPrompt = <<<'EOT'
You are an expert news editor. Your task is to analyze the provided text and rewrite it into a professional news report.

**Step 1: VALIDATION (Crucial)**
- Analyze the input content.
- If the content is **too short** (e.g., less than 50 words), just a "Read more" teaser, a login prompt, or lacks sufficient facts to build a story:
- **RETURN THIS JSON AND STOP:** {"skip": true, "reason": "Content is incomplete or a snippet"}

EOT;

            // Inject the Custom Prompt if provided, otherwise use default tone
            if (!empty(trim($customPrompt))) {
                $systemPrompt .= "\n**Step 2: CUSTOM INSTRUCTIONS (IMPORTANT)**\n";
                $systemPrompt .= "Apply the following specific instructions to your rewrite:\n";
                $systemPrompt .= "\"" . $customPrompt . "\"\n";
            } else {
                $systemPrompt .= "\n**Step 2: REWRITE RULES**\n";
                $systemPrompt .= "- Structure: Use many small, short paragraphs.\n";
                $systemPrompt .= "- Tone: Professional, objective, and simple.\n";
            }

            // Always enforce JSON output at the very end
            $systemPrompt .= <<<'EOT'

**Step 3: OUTPUT FORMAT (MANDATORY)**
- Return a **valid JSON object** with two keys:
   - "title": A professional headline.
   - "content": The rewritten article HTML (use <p> tags).
- NO HEADINGS: Do NOT use Markdown headings (#) inside the content body.
EOT;

            // --- 2. CALL API ---
            $responseString = "";

            if ($this->provider->provider_key === 'google-gemini') {
                $responseString = $this->callGemini($this->provider->api_endpoint, $apiKey, $model, $systemPrompt, $content);
            } else {
                $responseString = $this->callOpenAICompatible($this->provider->api_endpoint, $apiKey, $model, $systemPrompt, $content);
            }

            // --- 3. PROCESS RESPONSE ---
            if (!empty($responseString)) {
                
                // Clean and extract JSON
                $cleanJson = $this->cleanJsonBlock($responseString);
                
                // Decode
                $decoded = json_decode($cleanJson, true);

                // Validation
                if (json_last_error() === JSON_ERROR_NONE) {
                    
                    // CHECK FOR SKIP FLAG
                    if (isset($decoded['skip']) && $decoded['skip'] === true) {
                        return ['skip' => true, 'reason' => $decoded['reason'] ?? 'AI rejected content'];
                    }

                    if (isset($decoded['content'])) {
                        // Success: Convert markdown content to HTML
                        $decoded['content'] = Str::markdown($decoded['content']);
                        return $decoded;
                    }
                }

                // Fallback: If AI stubbornly returned plain text instead of JSON, we accept it as the content
                return [
                    'title' => null, // Let the controller fallback to original title
                    'content' => Str::markdown($responseString)
                ];
            }

            throw new \Exception("The AI Provider returned an empty response.");

        } catch (\Exception $e) {
            Log::error("AI Rewrite Failed [{$this->provider->provider_name}]: " . $e->getMessage());
            
            // Return the EXACT error to the frontend so the user knows if the API key is actually invalid!
            throw new \Exception($e->getMessage());
        }
    }

    private function cleanJsonBlock(string $text): string
    {
        $start = strpos($text, '{');
        $end = strrpos($text, '}');

        if ($start !== false && $end !== false && $end > $start) {
            return substr($text, $start, $end - $start + 1);
        }

        return trim($text); 
    }

    private function callGemini($endpoint, $apiKey, $model, $prompt, $content)
    {
        $url = rtrim($endpoint, '/') . "/{$model}:generateContent?key={$apiKey}";
        $payload = [
            "contents" => [[ "parts" => [[ "text" => $prompt . "\n\n--- ORIGINAL CONTENT ---\n" . $content ]] ]],
            "generationConfig" => [ "temperature" => 0.4, "maxOutputTokens" => 4000 ]
        ];

        // INCREASED TIMEOUT TO 120 SECONDS
        $response = Http::timeout(120)->post($url, $payload);

        if ($response->failed()) {
            throw new \Exception("Gemini API Error: " . ($response->json('error.message') ?? $response->body()));
        }

        return $response->json('candidates.0.content.parts.0.text') ?? '';
    }

    private function callOpenAICompatible($endpoint, $apiKey, $model, $prompt, $content)
    {
        // INCREASED TIMEOUT TO 120 SECONDS
        $response = Http::withToken($apiKey)->timeout(120)->post($endpoint, [
            "model" => $model,
            "messages" => [
                ["role" => "system", "content" => $prompt],
                ["role" => "user", "content" => $content]
            ],
            "temperature" => 0.4
        ]);

        if ($response->failed()) {
            throw new \Exception("AI API Error: " . ($response->json('error.message') ?? $response->body()));
        }

        return $response->json('choices.0.message.content') ?? '';
    }

    private function getDecryptedKey($encryptedKey)
    {
        try { 
            return Crypt::decryptString($encryptedKey); 
        } catch (\Exception $e) { 
            return $encryptedKey; 
        }
    }
}