<?php

namespace App\Services\Ai;

use App\Models\Setting;
use App\Models\TextAnalysisRequest;
use App\Modules\Ai\Services\OpenAiCompletionService;
use App\Modules\Users\Models\User;
use App\Services\Subscriptions\AiQuotaService;
use App\Services\Subscriptions\PlanCapabilities;
use App\Services\Subscriptions\StudioQuotaService;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\ValidationException;
use Throwable;

final class TextAnalysisService
{
    public function __construct(
        private readonly OpenAiCompletionService $ai,
        private readonly StudioQuotaService $studioQuota,
        private readonly AiQuotaService $quota,
        private readonly TextLimitService $textLimit,
    ) {}

    /**
     * @return array<string, mixed>
     */
    public function analyzeAndHumanize(User $user, string $text, string $mode = 'analyze_and_humanize'): array
    {
        if ($mode !== 'analyze_and_humanize') {
            throw ValidationException::withMessages([
                'mode' => ['وضع التحليل غير مدعوم.'],
            ]);
        }

        $settings = Setting::current();
        if (! $settings->ai_enabled) {
            throw ValidationException::withMessages([
                'text' => ['خدمة الذكاء الاصطناعي معطلة حالياً.'],
            ]);
        }

        $this->studioQuota->assertCanUse(
            $user,
            'text_analysis',
            'تحليل النص وتحسين الصياغة متاح ضمن خطط مدار.'
        );

        $this->textLimit->assertWithinLimit($user, $text);

        $plan = $this->quota->resolveEffectivePlan($user);
        $caps = PlanCapabilities::forPlan($plan);

        $record = TextAnalysisRequest::query()->create([
            'user_id' => $user->id,
            'original_text' => $text,
            'status' => TextAnalysisRequest::STATUS_PENDING,
        ]);

        try {
            $result = $this->ai->completeWithSystem(
                (string) config('text_analysis.system_prompt'),
                "Analyze and humanize the following text (Arabic or English). Preserve the original language unless a natural bilingual mix is already present:\n\n".$text,
                $user->id,
            );

            $parsed = $this->parseModelJson($result['response']);
            $record->update([
                'analysis_result' => trim((string) ($parsed['analysis'] ?? '')),
                'humanized_text' => (string) ($parsed['humanized_text'] ?? ''),
                'ai_probability_score' => $this->clampScore($parsed['ai_probability_score'] ?? null),
                'readability_score' => $this->clampScore($parsed['readability_score'] ?? null),
                'tone' => isset($parsed['tone']) ? mb_substr((string) $parsed['tone'], 0, 64) : null,
                'status' => TextAnalysisRequest::STATUS_COMPLETED,
                'tokens_used' => (int) ($result['tokens_used'] ?? 0),
            ]);

            $record->refresh();

            return $this->payloadForClient($user, $record, $caps, $parsed);
        } catch (Throwable $e) {
            Log::warning('text_analysis.failed', ['id' => $record->id, 'error' => $e->getMessage()]);
            $record->update([
                'status' => TextAnalysisRequest::STATUS_FAILED,
                'analysis_result' => $e->getMessage(),
            ]);

            throw $e;
        }
    }

    /**
     * @return array<string, mixed>
     */
    public function limitsForUser(User $user): array
    {
        $plan = $this->quota->resolveEffectivePlan($user);
        $wordLimits = $this->textLimit->limitsForUser($user);
        $summary = $this->studioQuota->featureSummary($user, 'text_analysis');

        return array_merge($wordLimits, [
            'daily' => $summary,
            'disclaimer' => (string) config('text_analysis.disclaimer_ar'),
        ]);
    }

    /**
     * @param  array<string, mixed>  $parsed
     * @return array<string, mixed>
     */
    private function payloadForClient(User $user, TextAnalysisRequest $record, array $caps, array $parsed = []): array
    {
        $recommendations = [];
        if (isset($parsed['recommendations']) && is_array($parsed['recommendations'])) {
            $recommendations = array_values(array_map('strval', $parsed['recommendations']));
        }

        $humanized = (string) ($record->humanized_text ?? '');
        $copyPolicy = $this->textLimit->humanizedCopyPolicy($user, $humanized);

        $aiScore = $record->ai_probability_score;
        $humanScore = $this->resolveHumanScore($parsed, $aiScore);

        $weakPoints = isset($parsed['weak_points']) && is_array($parsed['weak_points'])
            ? array_values(array_map('strval', $parsed['weak_points']))
            : [];

        return [
            'id' => $record->id,
            'status' => $record->status,
            'ai_probability_score' => $aiScore,
            'human_score' => $humanScore,
            'readability_score' => $record->readability_score,
            'tone' => $record->tone,
            'analysis' => $record->analysis_result,
            'weak_points' => $weakPoints,
            'humanized_text' => $humanized,
            'humanized_preview' => $copyPolicy['humanized_preview'],
            'humanized_locked' => $copyPolicy['humanized_locked'],
            'humanized_word_count' => $copyPolicy['humanized_word_count'],
            'recommendations' => $recommendations,
            'can_copy_full' => $copyPolicy['can_copy_full'],
            'can_export' => ! empty($caps['text_analysis_export']) || ! empty($caps['pdf_export']),
            'scores_note' => 'مؤشرات أسلوبية تقديرية وليست حكماً قطعياً',
            'disclaimer' => (string) config('text_analysis.disclaimer_ar'),
            'copy_upgrade_message' => $copyPolicy['copy_upgrade_message'],
            'tokens_used' => $record->tokens_used,
            'created_at' => $record->created_at?->toIso8601String(),
        ];
    }

    private function resolveHumanScore(array $parsed, ?int $aiScore): ?int
    {
        if (isset($parsed['human_score'])) {
            return $this->clampScore($parsed['human_score']);
        }
        if ($aiScore === null) {
            return null;
        }

        return max(0, min(100, 100 - $aiScore));
    }

    /**
     * @return array<string, mixed>
     */
    private function parseModelJson(string $raw): array
    {
        $trimmed = trim($raw);
        if (str_starts_with($trimmed, '```')) {
            $trimmed = preg_replace('/^```(?:json)?\s*/i', '', $trimmed) ?? $trimmed;
            $trimmed = preg_replace('/\s*```$/', '', $trimmed) ?? $trimmed;
        }

        $decoded = json_decode($trimmed, true);
        if (is_array($decoded)) {
            return $decoded;
        }

        if (preg_match('/\{[\s\S]*\}/', $trimmed, $m)) {
            $decoded = json_decode($m[0], true);
            if (is_array($decoded)) {
                return $decoded;
            }
        }

        throw new \RuntimeException('تعذر قراءة نتيجة التحليل من النموذج.');
    }

    private function clampScore(mixed $value): ?int
    {
        if ($value === null || $value === '') {
            return null;
        }
        $n = (int) $value;

        return max(0, min(100, $n));
    }

    /**
     * @return list<string>
     */
    private function extractWeakPointsFromAnalysis(?string $analysis): array
    {
        if ($analysis === null || $analysis === '') {
            return [];
        }
        if (! str_contains($analysis, 'نقاط الضعف:')) {
            return [];
        }
        $parts = explode('نقاط الضعف:', $analysis, 2);
        $block = trim($parts[1] ?? '');
        if ($block === '') {
            return [];
        }

        return array_values(array_filter(array_map(
            static fn (string $line) => ltrim(trim($line), '- '),
            preg_split('/\r\n|\r|\n/', $block) ?: []
        )));
    }
}
