<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\Anime;
use App\Models\Genre;
use App\Models\Setting;
use App\Models\SeoKeyword;
use App\Models\SeoRedirect;
use App\Models\Episode;
use App\Models\User;
use App\Models\Comment;
use App\Models\Watchlist;
use App\Models\AnimeRating;
use App\Models\BlogPost;
use App\Services\DeepSeekService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\DB;

class SeoController extends Controller
{
    private array $defaults = [
        'seo_site_name'           => 'Animexe',
        'seo_title_template'      => '%s — Animexe | Türkçe Anime İzle',
        'seo_home_title'          => 'Animexe — Türkçe Anime İzle | Ücretsiz HD',
        'seo_home_description'    => 'Animexe\'de binlerce anime dizisi ve filmini Türkçe altyazılı veya dublajlı, ücretsiz ve yüksek kalitede izleyin.',
        'seo_home_keywords'       => 'anime izle, türkçe anime, anime dizi, anime film, ücretsiz anime izle, hd anime, türkçe altyazılı anime, türkçe dublajlı anime',
        'seo_og_image'            => '/logo.jpg',
        'seo_twitter_site'        => '',
        'seo_facebook_app_id'     => '',
        'seo_canonical_domain'    => '',
        'seo_google_analytics'    => '',
        'seo_gtm_id'              => '',
        'seo_gsc_verification'    => '',
        'seo_bing_verification'   => '',
        'seo_yandex_verification' => '',
        'seo_enable_schema'       => '1',
        'seo_enable_breadcrumb'   => '1',
        'seo_noindex_search'      => '1',
        'seo_noindex_profile'     => '1',
        'seo_noindex_watch'       => '0',
        'seo_org_logo'            => '/logo.jpg',
        'seo_org_twitter'         => '',
        'seo_org_facebook'        => '',
        'seo_org_instagram'       => '',
        'seo_robots_custom'       => '',
        'seo_pagespeed_api_key'   => '',
        'seo_looker_embed_url'    => '',
        'seo_enable_faq_schema'   => '1',
        'seo_enable_video_schema' => '1',
    ];

    public function index()
    {
        $settings = Setting::where('key', 'like', 'seo_%')->pluck('value', 'key')->toArray();
        foreach ($this->defaults as $key => $val) {
            if (!array_key_exists($key, $settings)) {
                $settings[$key] = $val;
            }
        }

        $robotsPath = public_path('robots.txt');
        $robotsTxt  = File::exists($robotsPath) ? File::get($robotsPath) : '';
        $audit      = $this->runAudit();

        $sitemapStats = [
            'anime_count'  => Anime::where('is_published', true)->count(),
            'genre_count'  => Genre::where('is_active', true)->count(),
            'static_count' => 2,
            'last_updated' => Setting::get('seo_sitemap_generated_at', null),
        ];

        // Keyword tracker
        $keywords = SeoKeyword::orderBy('keyword')->get();

        // Redirect manager
        $redirects = SeoRedirect::orderByDesc('hits')->paginate(25, ['*'], 'rpage');

        // Bulk SEO — animelerin SEO verileri (seo_title veya seo_meta_desc eksik olanlar önce)
        $animes = Anime::where('is_published', true)
            ->orderByRaw('(seo_title IS NULL OR seo_title = "") DESC')
            ->orderBy('title')
            ->select('id', 'title', 'slug', 'description', 'seo_title', 'seo_meta_desc', 'seo_keywords')
            ->paginate(30, ['*'], 'apage');

        $animeSeoCoverage = [
            'total'        => Anime::where('is_published', true)->count(),
            'has_seo_title'=> Anime::where('is_published', true)->whereNotNull('seo_title')->where('seo_title', '!=', '')->count(),
            'has_seo_desc' => Anime::where('is_published', true)->whereNotNull('seo_meta_desc')->where('seo_meta_desc', '!=', '')->count(),
        ];

        // Image alt audit — animes with cover
        $missingAlt = Anime::where('is_published', true)
            ->whereNotNull('cover_image')->where('cover_image', '!=', '')
            ->whereNull('title')->count(); // titles serve as alt text, so just check no-title

        // Duplicate descriptions
        $dupDesc = DB::table('animes')
            ->select('description', DB::raw('COUNT(*) as cnt'))
            ->where('is_published', true)
            ->whereNotNull('description')
            ->where('description', '!=', '')
            ->groupBy('description')
            ->having('cnt', '>', 1)
            ->count();

        // ── Analytics stats for Google tab ───────────────────────────────────
        $analyticsStats = [
            'total_anime'       => Anime::where('is_published', true)->count(),
            'total_episodes'    => class_exists(Episode::class) ? Episode::count() : 0,
            'total_users'       => User::count(),
            'total_genres'      => Genre::where('is_active', true)->count(),
            'total_comments'    => class_exists(Comment::class) ? Comment::count() : 0,
            'total_watchlists'  => class_exists(Watchlist::class) ? Watchlist::count() : 0,
            'total_ratings'     => class_exists(AnimeRating::class) ? AnimeRating::count() : 0,
            'total_blog_posts'  => class_exists(BlogPost::class) ? BlogPost::count() : 0,
            'total_redirects'   => SeoRedirect::where('is_active', true)->count(),
            'total_redirect_hits'=> SeoRedirect::sum('hits'),
            'seo_title_pct'     => $sitemapStats['anime_count'] > 0
                ? round($animeSeoCoverage['has_seo_title'] / $sitemapStats['anime_count'] * 100)
                : 0,
            'seo_desc_pct'      => $sitemapStats['anime_count'] > 0
                ? round($animeSeoCoverage['has_seo_desc'] / $sitemapStats['anime_count'] * 100)
                : 0,
            'new_anime_this_month' => Anime::where('is_published', true)
                ->where('created_at', '>=', now()->startOfMonth())->count(),
            'new_users_this_month' => User::where('created_at', '>=', now()->startOfMonth())->count(),
        ];

        // Integration status
        $integrations = [
            'ga4'    => !empty($settings['seo_google_analytics'] ?? ''),
            'gtm'    => !empty($settings['seo_gtm_id'] ?? ''),
            'gsc'    => !empty($settings['seo_gsc_verification'] ?? ''),
            'bing'   => !empty($settings['seo_bing_verification'] ?? ''),
            'yandex' => !empty($settings['seo_yandex_verification'] ?? ''),
        ];

        return view('admin.seo.index', compact(
            'settings', 'robotsTxt', 'audit', 'sitemapStats',
            'keywords', 'redirects', 'animes', 'animeSeoCoverage', 'dupDesc',
            'analyticsStats', 'integrations'
        ));
    }

    public function update(Request $request)
    {
        // Tüm alanlar opsiyonel — her tab kendi alanlarını gönderir (partial update)
        $rules = [
            'seo_site_name'           => 'nullable|string|max:100',
            'seo_title_template'      => 'nullable|string|max:200',
            'seo_home_title'          => 'nullable|string|max:200',
            'seo_home_description'    => 'nullable|string|max:500',
            'seo_home_keywords'       => 'nullable|string|max:500',
            'seo_og_image'            => 'nullable|string|max:500',
            'seo_twitter_site'        => 'nullable|string|max:100',
            'seo_facebook_app_id'     => 'nullable|string|max:100',
            'seo_canonical_domain'    => 'nullable|url|max:200',
            'seo_google_analytics'    => 'nullable|string|max:50',
            'seo_gtm_id'              => 'nullable|string|max:50',
            'seo_gsc_verification'    => 'nullable|string|max:200',
            'seo_bing_verification'   => 'nullable|string|max:200',
            'seo_yandex_verification' => 'nullable|string|max:200',
            'seo_org_logo'            => 'nullable|string|max:500',
            'seo_org_twitter'         => 'nullable|string|max:200',
            'seo_org_facebook'        => 'nullable|string|max:200',
            'seo_org_instagram'       => 'nullable|string|max:200',
            'seo_pagespeed_api_key'   => 'nullable|string|max:100',
            'seo_looker_embed_url'    => 'nullable|string|max:500',
        ];

        $validated = $request->validate($rules);

        // Checkbox alanları: sadece request'te varsa güncelle
        $checkboxes = [
            'seo_enable_schema', 'seo_enable_breadcrumb', 'seo_noindex_search',
            'seo_noindex_profile', 'seo_noindex_watch', 'seo_enable_faq_schema', 'seo_enable_video_schema',
        ];
        foreach ($checkboxes as $key) {
            if ($request->has($key) || $request->has('_seo_section')) {
                $value = $request->input($key);
                $validated[$key] = ($value === '1' || $value === 'on') ? '1' : '0';
            }
        }

        // Sadece gönderilen (non-null) alanları kaydet
        foreach ($validated as $key => $value) {
            if ($value !== null) {
                Setting::set($key, $value, 'seo');
            }
        }

        cache()->forget('seo_settings');

        if ($request->wantsJson()) {
            return response()->json(['ok' => true, 'message' => 'SEO ayarları kaydedildi.']);
        }
        return back()->with('success', 'SEO ayarları başarıyla kaydedildi.');
    }

    public function updateRobots(Request $request)
    {
        $request->validate(['robots_txt' => 'required|string|max:10000']);
        File::put(public_path('robots.txt'), $request->input('robots_txt'));
        return back()->with('success', 'robots.txt güncellendi.');
    }

    public function pingSearchEngines(Request $request)
    {
        $domain     = rtrim(Setting::get('seo_canonical_domain', config('app.url')), '/');
        $sitemapUrl = urlencode($domain . '/sitemap.xml');
        $results    = [];

        foreach (['google' => "https://www.google.com/ping?sitemap={$sitemapUrl}", 'bing' => "https://www.bing.com/ping?sitemap={$sitemapUrl}"] as $engine => $url) {
            try {
                $r = Http::timeout(5)->get($url);
                $results[$engine] = $r->successful() ? 'success' : 'error';
            } catch (\Throwable) {
                $results[$engine] = 'error';
            }
        }

        Setting::set('seo_sitemap_pinged_at', now()->toDateTimeString(), 'seo');
        return back()->with('ping_results', $results)->with('success', 'Arama motorlarına bildirim gönderildi.');
    }

    public function auditJson()
    {
        return response()->json($this->runAudit());
    }

    // ── Keyword Tracker ───────────────────────────────────────────────────────

    public function storeKeyword(Request $request)
    {
        $data = $request->validate([
            'keyword'       => 'required|string|max:255',
            'target_url'    => 'nullable|string|max:500',
            'search_volume' => 'nullable|integer|min:0',
            'difficulty'    => 'nullable|integer|min:0|max:100',
            'notes'         => 'nullable|string|max:1000',
        ]);
        SeoKeyword::create($data);
        return back()->with('success', 'Anahtar kelime eklendi.');
    }

    public function destroyKeyword(SeoKeyword $keyword)
    {
        $keyword->delete();
        return back()->with('success', 'Anahtar kelime silindi.');
    }

    // ── Redirect Manager ─────────────────────────────────────────────────────

    public function storeRedirect(Request $request)
    {
        $data = $request->validate([
            'from_path' => 'required|string|max:500',
            'to_path'   => 'required|string|max:500',
            'type'      => 'required|in:301,302',
        ]);

        $data['from_path'] = '/' . ltrim($data['from_path'], '/');

        SeoRedirect::updateOrCreate(['from_path' => $data['from_path']], $data);
        cache()->forget('seo_redirect_' . md5($data['from_path']));
        return back()->with('success', 'Yönlendirme eklendi/güncellendi.');
    }

    public function destroyRedirect(SeoRedirect $redirect)
    {
        cache()->forget('seo_redirect_' . md5($redirect->from_path));
        $redirect->delete();
        return back()->with('success', 'Yönlendirme silindi.');
    }

    public function toggleRedirect(SeoRedirect $redirect)
    {
        $redirect->update(['is_active' => !$redirect->is_active]);
        cache()->forget('seo_redirect_' . md5($redirect->from_path));
        return response()->json(['is_active' => $redirect->is_active]);
    }

    // ── Bulk Anime SEO ────────────────────────────────────────────────────────

    public function bulkSaveAnime(Request $request)
    {
        $data = $request->validate([
            'animes'                   => 'required|array',
            'animes.*.id'              => 'required|integer|exists:animes,id',
            'animes.*.seo_title'       => 'nullable|string|max:100',
            'animes.*.seo_meta_desc'   => 'nullable|string|max:320',
            'animes.*.seo_keywords'    => 'nullable|string|max:500',
        ]);

        foreach ($data['animes'] as $row) {
            Anime::where('id', $row['id'])->update([
                'seo_title'     => $row['seo_title']    ?? null,
                'seo_meta_desc' => $row['seo_meta_desc'] ?? null,
                'seo_keywords'  => $row['seo_keywords']  ?? null,
            ]);
        }

        return back()->with('success', count($data['animes']) . ' anime için SEO verileri kaydedildi.');
    }

    public function generateAnimeSeo(Anime $anime)
    {
        $title    = trim($anime->title);
        $seoTitle = $title . ' — Türkçe ' . ($anime->type === 'movie' ? 'Anime Film' : 'Anime Dizi') . ' | Animexe';
        $seoTitle = mb_substr($seoTitle, 0, 70);

        $desc = $anime->description
            ? mb_substr(strip_tags($anime->description), 0, 130)
            : '';
        $seoDesc = $desc
            ? $desc . ' Animexe\'de Türkçe altyazılı izle.'
            : $title . '\'yi Türkçe altyazılı veya dublajlı, ücretsiz ve HD kalitede Animexe\'de izleyin.';
        $seoDesc = mb_substr($seoDesc, 0, 160);

        $keywords = strtolower($title) . ' izle, ' . strtolower($title) . ' türkçe, ' . strtolower($title) . ' türkçe altyazılı';

        $anime->update([
            'seo_title'     => $seoTitle,
            'seo_meta_desc' => $seoDesc,
            'seo_keywords'  => $keywords,
        ]);

        return response()->json([
            'seo_title'     => $seoTitle,
            'seo_meta_desc' => $seoDesc,
            'seo_keywords'  => $keywords,
        ]);
    }

    public function bulkGenerateAllSeo(Request $request)
    {
        $animes = Anime::where('is_published', true)
            ->where(fn($q) => $q->whereNull('seo_title')->orWhere('seo_title', ''))
            ->get(['id', 'title', 'type', 'description']);

        $count = 0;
        foreach ($animes as $anime) {
            $title    = trim($anime->title);
            $seoTitle = mb_substr($title . ' — Türkçe ' . ($anime->type === 'movie' ? 'Anime Film' : 'Anime Dizi') . ' | Animexe', 0, 70);
            $desc     = $anime->description ? mb_substr(strip_tags($anime->description), 0, 130) : '';
            $seoDesc  = mb_substr($desc ? $desc . ' Animexe\'de Türkçe izle.' : $title . '\'yi Animexe\'de ücretsiz izleyin.', 0, 160);
            $keywords = strtolower($title) . ' izle, ' . strtolower($title) . ' türkçe altyazılı';

            $anime->update([
                'seo_title'     => $seoTitle,
                'seo_meta_desc' => $seoDesc,
                'seo_keywords'  => $keywords,
            ]);
            $count++;
        }

        return response()->json(['generated' => $count]);
    }

    /**
     * DeepSeek ile toplu AI SEO üretimi — SEO başlığı olmayan animeleri işler.
     * Her batch 10 anime, aralarında 1s bekleme (rate limit önlemi).
     * İstek başına max 10 anime işler; frontend'den tekrar tekrar çağrılarak tamamlanır.
     */
    public function aiBulkGenerateSeo(Request $request)
    {
        $ai = new DeepSeekService();
        if (!$ai->isConfigured()) {
            return response()->json(['error' => 'DeepSeek API Key tanımlı değil.'], 422);
        }

        $batchSize = min((int)$request->input('batch', 10), 20);

        $animes = Anime::where('is_published', true)
            ->where(fn($q) => $q->whereNull('seo_title')->orWhere('seo_title', ''))
            ->with('genres:id,name')
            ->limit($batchSize)
            ->get();

        $remaining = Anime::where('is_published', true)
            ->where(fn($q) => $q->whereNull('seo_title')->orWhere('seo_title', ''))
            ->count();

        $done = 0;
        $errors = 0;

        foreach ($animes as $anime) {
            $result = $ai->generateAnimeSeoMeta($anime);
            if ($result) {
                $anime->update([
                    'seo_title'     => $result['seo_title']     ?? null,
                    'seo_meta_desc' => $result['seo_meta_desc'] ?? null,
                    'seo_keywords'  => $result['seo_keywords']  ?? null,
                ]);
                $done++;
            } else {
                $errors++;
            }
            sleep(1); // DeepSeek rate limit
        }

        return response()->json([
            'done'      => $done,
            'errors'    => $errors,
            'remaining' => max(0, $remaining - $done),
        ]);
    }

    // ── PageSpeed ─────────────────────────────────────────────────────────────

    public function pagespeedCheck(Request $request)
    {
        $request->validate(['url' => 'required|url', 'strategy' => 'in:mobile,desktop']);

        $apiKey  = Setting::get('seo_pagespeed_api_key', '');
        $url     = $request->url;
        $strategy = $request->input('strategy', 'mobile');

        if (empty($apiKey)) {
            return response()->json(['error' => 'PageSpeed API anahtarı girilmemiş. SEO ayarlarından ekleyin.'], 422);
        }

        try {
            $endpoint = "https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=" . urlencode($url) . "&strategy={$strategy}&key={$apiKey}";
            $resp = Http::timeout(20)->get($endpoint);

            if (!$resp->successful()) {
                return response()->json(['error' => 'PageSpeed API hatası: ' . $resp->status()], 422);
            }

            $data       = $resp->json();
            $categories = $data['lighthouseResult']['categories'] ?? [];
            $audits     = $data['lighthouseResult']['audits'] ?? [];

            $scores = [
                'performance'   => round(($categories['performance']['score']   ?? 0) * 100),
                'accessibility' => round(($categories['accessibility']['score'] ?? 0) * 100),
                'seo'           => round(($categories['seo']['score']           ?? 0) * 100),
                'best_practices'=> round(($categories['best-practices']['score'] ?? 0) * 100),
            ];

            $opportunities = [];
            foreach ($audits as $id => $audit) {
                if (($audit['score'] ?? 1) < 0.9 && isset($audit['details']['type']) && $audit['details']['type'] === 'opportunity') {
                    $opportunities[] = [
                        'title'       => $audit['title'],
                        'description' => $audit['description'] ?? '',
                        'savings'     => $audit['details']['overallSavingsMs'] ?? null,
                    ];
                }
            }

            $fcp = $audits['first-contentful-paint']['displayValue'] ?? null;
            $lcp = $audits['largest-contentful-paint']['displayValue'] ?? null;
            $cls = $audits['cumulative-layout-shift']['displayValue'] ?? null;
            $tbt = $audits['total-blocking-time']['displayValue'] ?? null;

            return response()->json([
                'scores'        => $scores,
                'vitals'        => compact('fcp', 'lcp', 'cls', 'tbt'),
                'opportunities' => array_slice($opportunities, 0, 8),
            ]);
        } catch (\Throwable $e) {
            return response()->json(['error' => $e->getMessage()], 500);
        }
    }

    // ── Internal Links Audit ──────────────────────────────────────────────────

    public function internalLinksAudit()
    {
        // Find animes with no other anime referencing them in descriptions (orphaned)
        $allAnimes = Anime::where('is_published', true)->get(['id', 'title', 'slug']);
        $result    = [];

        foreach ($allAnimes as $anime) {
            $mentionedIn = Anime::where('is_published', true)
                ->where('id', '!=', $anime->id)
                ->where('description', 'like', '%' . $anime->title . '%')
                ->count();
            $result[] = [
                'id'          => $anime->id,
                'title'       => $anime->title,
                'slug'        => $anime->slug,
                'mentioned_in'=> $mentionedIn,
            ];
        }

        usort($result, fn($a, $b) => $a['mentioned_in'] <=> $b['mentioned_in']);

        return response()->json(array_slice($result, 0, 50));
    }

    // ── Duplicate Content ─────────────────────────────────────────────────────

    public function duplicateContent()
    {
        $dups = DB::table('animes')
            ->select('description', DB::raw('COUNT(*) as cnt'), DB::raw('GROUP_CONCAT(title ORDER BY title SEPARATOR ", ") as titles'))
            ->where('is_published', true)
            ->whereNotNull('description')
            ->where('description', '!=', '')
            ->groupBy('description')
            ->having('cnt', '>', 1)
            ->get();

        return response()->json($dups);
    }

    // ── AI SEO Methods ────────────────────────────────────────────────────────

    public function aiChat(Request $request)
    {
        $request->validate(['messages' => 'required|array', 'messages.*.role' => 'required|in:user,assistant', 'messages.*.content' => 'required|string|max:4000']);

        $ai = new DeepSeekService();
        if (!$ai->isConfigured()) {
            return response()->json(['error' => 'DeepSeek API Key tanımlı değil. Ayarlar sayfasından ekleyin.'], 422);
        }

        $total    = Anime::where('is_published', true)->count();
        $covered  = Anime::where('is_published', true)->whereNotNull('seo_title')->where('seo_title', '!=', '')->count();
        $audit    = $this->runAudit();
        $sitemap  = $total + Genre::where('is_active', true)->count() + 2;

        $context  = [
            'anime_count'   => $total,
            'seo_covered'   => $covered,
            'seo_score'     => $audit['score'],
            'sitemap_urls'  => $sitemap,
        ];

        $reply = $ai->seoChat($request->messages, $context);

        if (!$reply) {
            return response()->json(['error' => 'DeepSeek yanıt vermedi. API anahtarını kontrol edin.'], 500);
        }

        return response()->json(['reply' => $reply]);
    }

    public function aiGenerateAnimeSeo(Anime $anime)
    {
        $ai = new DeepSeekService();
        if (!$ai->isConfigured()) {
            return response()->json(['error' => 'DeepSeek API Key tanımlı değil.'], 422);
        }

        $anime->loadMissing('genres');
        $result = $ai->generateAnimeSeoMeta($anime);

        if (!$result) {
            return response()->json(['error' => 'AI yanıt vermedi.'], 500);
        }

        $anime->update([
            'seo_title'     => $result['seo_title']     ?? null,
            'seo_meta_desc' => $result['seo_meta_desc'] ?? null,
            'seo_keywords'  => $result['seo_keywords']  ?? null,
        ]);

        return response()->json($result);
    }

    public function aiKeywordSuggest(Request $request)
    {
        $request->validate(['topic' => 'required|string|max:200']);

        $ai = new DeepSeekService();
        if (!$ai->isConfigured()) {
            return response()->json(['error' => 'DeepSeek API Key tanımlı değil.'], 422);
        }

        $result = $ai->suggestKeywords($request->topic);
        if (!$result) {
            return response()->json(['error' => 'AI yanıt vermedi.'], 500);
        }

        return response()->json($result);
    }

    public function aiPageAnalysis(Request $request)
    {
        $request->validate(['url' => 'required|url', 'title' => 'nullable|string', 'description' => 'nullable|string', 'content' => 'nullable|string']);

        $ai = new DeepSeekService();
        if (!$ai->isConfigured()) {
            return response()->json(['error' => 'DeepSeek API Key tanımlı değil.'], 422);
        }

        $result = $ai->analyzePageSeo(
            $request->url,
            $request->input('title', ''),
            $request->input('description', ''),
            $request->input('content', '')
        );

        if (!$result) {
            return response()->json(['error' => 'AI yanıt vermedi.'], 500);
        }

        return response()->json($result);
    }

    public function aiFaqSchema(Request $request)
    {
        $request->validate(['anime_id' => 'required|integer|exists:animes,id']);

        $ai    = new DeepSeekService();
        if (!$ai->isConfigured()) {
            return response()->json(['error' => 'DeepSeek API Key tanımlı değil.'], 422);
        }

        $anime  = Anime::with('genres')->findOrFail($request->anime_id);
        $result = $ai->generateFaqSchema($anime);

        if (!$result) {
            return response()->json(['error' => 'AI yanıt vermedi.'], 500);
        }

        return response()->json($result);
    }

    public function aiContentStrategy(Request $request)
    {
        $ai = new DeepSeekService();
        if (!$ai->isConfigured()) {
            return response()->json(['error' => 'DeepSeek API Key tanımlı değil.'], 422);
        }

        $total   = Anime::where('is_published', true)->count();
        $covered = Anime::where('is_published', true)->whereNotNull('seo_title')->where('seo_title', '!=', '')->count();
        $audit   = $this->runAudit();
        $kwds    = SeoKeyword::orderBy('search_volume', 'desc')->take(10)->pluck('keyword')->toArray();

        $strategy = $ai->generateContentStrategy([
            'seo_score'   => $audit['score'],
            'anime_count' => $total,
            'seo_covered' => $covered,
        ], $kwds);

        if (!$strategy) {
            return response()->json(['error' => 'AI yanıt vermedi.'], 500);
        }

        return response()->json(['strategy' => $strategy]);
    }

    public function aiRobotsTxt(Request $request)
    {
        $ai = new DeepSeekService();
        if (!$ai->isConfigured()) {
            return response()->json(['error' => 'DeepSeek API Key tanımlı değil.'], 422);
        }

        $domain = Setting::get('seo_canonical_domain', 'animexe.com');
        $result = $ai->generateRobotsTxt($domain);

        if (!$result) {
            return response()->json(['error' => 'AI yanıt vermedi.'], 500);
        }

        return response()->json(['robots_txt' => $result]);
    }

    // ── Toplu Doldurma (Batch) ────────────────────────────────────────────────

    /**
     * Yayınlanan animelerin coverage istatistiklerini döndür.
     * GET /admin/seo/bulk-fill-stats
     */
    public function bulkFillStats()
    {
        $total       = Anime::where('is_published', true)->count();
        $hasDesc     = Anime::where('is_published', true)->whereNotNull('description')->where('description', '!=', '')->count();
        $hasSeoTitle = Anime::where('is_published', true)->whereNotNull('seo_title')->where('seo_title', '!=', '')->count();
        $hasSeoDesc  = Anime::where('is_published', true)->whereNotNull('seo_meta_desc')->where('seo_meta_desc', '!=', '')->count();
        $hasYear     = Anime::where('is_published', true)->whereNotNull('release_year')->count();
        $hasGenres   = Anime::where('is_published', true)->has('genres')->count();

        // Kaç adet işlenecek (her mode için)
        $needsSeo    = Anime::where('is_published', true)->where(fn($q) => $q->whereNull('seo_title')->orWhere('seo_title', ''))->count();
        $needsMeta   = Anime::where('is_published', true)->where(fn($q) =>
            $q->whereNull('description')->orWhere('description', '')
              ->orWhereNull('release_year')
        )->count();
        $needsAll    = Anime::where('is_published', true)->where(fn($q) =>
            $q->whereNull('seo_title')->orWhere('seo_title', '')
              ->orWhereNull('description')->orWhere('description', '')
        )->count();

        return response()->json([
            'total'        => $total,
            'has_desc'     => $hasDesc,
            'has_seo_title'=> $hasSeoTitle,
            'has_seo_desc' => $hasSeoDesc,
            'has_year'     => $hasYear,
            'has_genres'   => $hasGenres,
            'needs_seo'    => $needsSeo,
            'needs_meta'   => $needsMeta,
            'needs_all'    => $needsAll,
            'pct_seo'      => $total > 0 ? round($hasSeoTitle / $total * 100) : 0,
            'pct_desc'     => $total > 0 ? round($hasDesc / $total * 100) : 0,
        ]);
    }

    /**
     * Toplu doldurma — batch tabanlı, timeout olmaz.
     *
     * POST /admin/seo/bulk-fill-batch
     * body: {
     *   mode: 'template_seo' | 'ai_seo' | 'ai_meta' | 'ai_all',
     *   last_id: 0,          // son işlenen anime id'si (pagination için)
     *   batch_size: 5,       // kaç anime işlensin
     *   force: false,        // dolu alanları da üzerine yaz
     * }
     * returns: { done, errors, last_id, remaining, total }
     */
    public function bulkFillBatch(Request $request)
    {
        $mode      = $request->input('mode', 'template_seo');
        $lastId    = (int) $request->input('last_id', 0);
        $batchSize = min((int) $request->input('batch_size', 10), 50);
        $force     = $request->boolean('force', false);

        $isAi = str_starts_with($mode, 'ai_');

        if ($isAi) {
            $ai = new DeepSeekService();
            if (!$ai->isConfigured()) {
                return response()->json(['error' => 'DeepSeek API Key tanımlı değil. Ayarlar > DeepSeek ekleyin.'], 422);
            }
        }

        // Hangi animelere ihtiyaç var?
        $query = Anime::where('is_published', true)->where('id', '>', $lastId);

        if (!$force) {
            if ($mode === 'template_seo' || $mode === 'ai_seo') {
                $query->where(fn($q) => $q->whereNull('seo_title')->orWhere('seo_title', ''));
            } elseif ($mode === 'ai_meta') {
                $query->where(fn($q) =>
                    $q->whereNull('description')->orWhere('description', '')
                      ->orWhereNull('release_year')
                );
            } elseif ($mode === 'ai_all') {
                $query->where(fn($q) =>
                    $q->whereNull('seo_title')->orWhere('seo_title', '')
                      ->orWhereNull('description')->orWhere('description', '')
                );
            }
        }

        $total     = $query->clone()->count();
        $animes    = $query->with('genres:id,name')->orderBy('id')->limit($batchSize)->get();

        $done      = 0;
        $errors    = 0;
        $newLastId = $lastId;

        foreach ($animes as $anime) {
            $newLastId = $anime->id;

            try {
                if ($mode === 'template_seo') {
                    // Hızlı template — AI çağrısı yok
                    $title    = trim($anime->title);
                    $seoTitle = mb_substr(
                        $title . ' — Türkçe ' . ($anime->type === 'movie' ? 'Anime Film' : 'Anime') . ' İzle | Animexe',
                        0, 70
                    );
                    $desc     = $anime->description ? mb_substr(strip_tags($anime->description), 0, 130) : '';
                    $seoDesc  = mb_substr(
                        $desc
                            ? $desc . ' Animexe\'de Türkçe altyazılı izle.'
                            : $title . '\'yi Türkçe altyazılı veya dublajlı ücretsiz HD olarak Animexe\'de izleyin.',
                        0, 160
                    );
                    $kwds = strtolower($title) . ' izle, ' . strtolower($title) . ' türkçe altyazılı, ' . strtolower($title) . ' türkçe dublaj';

                    $updates = ['seo_title' => $seoTitle, 'seo_meta_desc' => $seoDesc, 'seo_keywords' => $kwds];
                    if ($force) {
                        $anime->update($updates);
                    } else {
                        $anime->update(array_filter($updates, fn($v) => !empty($v)));
                    }
                    $done++;

                } elseif ($mode === 'ai_seo') {
                    $result = $ai->generateAnimeSeoMeta($anime);
                    if ($result) {
                        $updates = array_filter([
                            'seo_title'     => $result['seo_title']     ?? null,
                            'seo_meta_desc' => $result['seo_meta_desc'] ?? null,
                            'seo_keywords'  => $result['seo_keywords']  ?? null,
                        ]);
                        if ($force || empty($anime->seo_title)) {
                            $anime->update($updates);
                        }
                        $done++;
                    } else {
                        $errors++;
                    }

                } elseif ($mode === 'ai_meta') {
                    $meta = $ai->generateAnimeMeta($anime->title, $anime->title_jp ?? '');
                    if ($meta) {
                        $this->applyAnimeMeta($anime, $meta, $force);
                        $done++;
                    } else {
                        $errors++;
                    }

                } elseif ($mode === 'ai_all') {
                    // Meta + SEO birlikte — 2 AI çağrısı
                    $meta = $ai->generateAnimeMeta($anime->title, $anime->title_jp ?? '');
                    if ($meta) {
                        $this->applyAnimeMeta($anime->fresh(), $meta, $force);
                    }

                    $anime->loadMissing('genres');
                    $seoResult = $ai->generateAnimeSeoMeta($anime->fresh(['genres']));
                    if ($seoResult) {
                        $anime->update(array_filter([
                            'seo_title'     => $seoResult['seo_title']     ?? null,
                            'seo_meta_desc' => $seoResult['seo_meta_desc'] ?? null,
                            'seo_keywords'  => $seoResult['seo_keywords']  ?? null,
                        ]));
                        $done++;
                    } else {
                        $errors++;
                    }
                }

            } catch (\Throwable $e) {
                $errors++;
                \Illuminate\Support\Facades\Log::warning("[bulkFillBatch] Hata [{$anime->id}] {$anime->title}: " . $e->getMessage());
            }

            // AI çağrıları arası kısa bekleme (rate limit önlemi)
            if ($isAi && $done + $errors < count($animes)) {
                usleep(800_000); // 0.8s
            }
        }

        // Kalan animeler (bu batch'ten sonra)
        $remaining = max(0, $total - $done - $errors);

        return response()->json([
            'done'      => $done,
            'errors'    => $errors,
            'last_id'   => $newLastId,
            'remaining' => $remaining,
            'total'     => $total,
            'finished'  => $animes->count() < $batchSize || $remaining === 0,
        ]);
    }

    private function applyAnimeMeta(Anime $anime, array $meta, bool $force): void
    {
        $updates = [];
        $fill    = function (string $field, $value) use ($anime, $force, &$updates) {
            if ($value === null || $value === '') return;
            if ($force || empty($anime->$field)) $updates[$field] = $value;
        };

        $fill('description',  $meta['description']  ?? null);
        $fill('release_year', $meta['release_year'] ?? null);
        $fill('studio',       $meta['studio']       ?? null);
        $fill('type',         $meta['type']         ?? null);
        $fill('status',       $meta['status']       ?? null);
        $fill('title_en',     $meta['title_en']     ?? null);
        $fill('title_jp',     $meta['title_jp']     ?? null);
        if (!empty($meta['rating']) && ($force || !$anime->rating)) {
            $updates['rating'] = min(10, max(0, (float) $meta['rating']));
        }

        if (!empty($updates)) $anime->update($updates);

        if (!empty($meta['genres']) && ($force || $anime->genres->isEmpty())) {
            $ids = [];
            foreach ($meta['genres'] as $name) {
                $g = \App\Models\Genre::firstOrCreate(
                    ['name' => $name],
                    ['slug' => \Illuminate\Support\Str::slug($name)]
                );
                $ids[] = $g->id;
            }
            if ($ids) {
                $force ? $anime->genres()->sync($ids) : $anime->genres()->syncWithoutDetaching($ids);
            }
        }
    }

    // ── Private ───────────────────────────────────────────────────────────────

    private function runAudit(): array
    {
        $total     = Anime::where('is_published', true)->count();
        $noDesc    = Anime::where('is_published', true)->where(fn($q) => $q->whereNull('description')->orWhere('description', ''))->count();
        $noCover   = Anime::where('is_published', true)->where(fn($q) => $q->whereNull('cover_image')->orWhere('cover_image', ''))->count();
        $shortDesc = Anime::where('is_published', true)->whereNotNull('description')->whereRaw('CHAR_LENGTH(description) < 100')->count();
        $noSlug    = Anime::where('is_published', true)->where(fn($q) => $q->whereNull('slug')->orWhere('slug', ''))->count();
        $noSeoTitle = Anime::where('is_published', true)->where(fn($q) => $q->whereNull('seo_title')->orWhere('seo_title', ''))->count();

        $seo     = Setting::where('key', 'like', 'seo_%')->pluck('value', 'key');
        $robots  = File::exists(public_path('robots.txt')) ? File::get(public_path('robots.txt')) : '';
        $hasSitemap = file_exists(public_path('sitemap.xml'));

        $dupDesc = DB::table('animes')->select('description')->where('is_published', true)
            ->whereNotNull('description')->where('description', '!=', '')
            ->groupBy('description')->havingRaw('COUNT(*) > 1')->count();

        $checks = [];

        // Site config
        $checks[] = $this->check('site_name',       !empty($seo['seo_site_name']),        'Site Adı Ayarlandı',                 'Site adı eksik',                      10);
        $checks[] = $this->check('home_title',       !empty($seo['seo_home_title']),       'Anasayfa Başlığı Mevcut',             'Anasayfa başlığı eksik',              10);
        $checks[] = $this->check('home_desc',        !empty($seo['seo_home_description']), 'Anasayfa Meta Açıklaması Mevcut',    'Anasayfa meta açıklaması eksik',      10);
        $checks[] = $this->check('title_length',     strlen($seo['seo_home_title'] ?? '') <= 70 && strlen($seo['seo_home_title'] ?? '') >= 30, 'Başlık Uzunluğu İdeal (30–70)', 'Başlık çok kısa veya çok uzun', 5);
        $checks[] = $this->check('desc_length',      strlen($seo['seo_home_description'] ?? '') <= 160 && strlen($seo['seo_home_description'] ?? '') >= 100, 'Meta Açıklama Uzunluğu İdeal', 'Meta açıklama 100–160 karakter arası olmalı', 5);
        $checks[] = $this->check('og_image',         !empty($seo['seo_og_image']),         'OG Görseli Tanımlandı',              'Varsayılan OG görseli eksik',         8);
        $checks[] = $this->check('canonical',        !empty($seo['seo_canonical_domain']), 'Canonical Domain Ayarlı',            'Canonical domain ayarlanmamış',       8);
        $checks[] = $this->check('analytics',        !empty($seo['seo_google_analytics']), 'Google Analytics Entegre',           'GA4 ID girilmemiş',                   7);
        $checks[] = $this->check('gsc',              !empty($seo['seo_gsc_verification']), 'Search Console Doğrulandı',          'GSC doğrulama kodu eksik',            7);
        $checks[] = $this->check('schema',           ($seo['seo_enable_schema'] ?? '1') === '1', 'Schema.org İşaretleme Aktif', 'Schema.org işaretleme kapalı',        7);
        $checks[] = $this->check('faq_schema',       ($seo['seo_enable_faq_schema'] ?? '1') === '1', 'FAQ Schema Aktif',       'FAQ şema kapalı (rich snippets kayıp)', 5);
        $checks[] = $this->check('video_schema',     ($seo['seo_enable_video_schema'] ?? '1') === '1', 'Video Schema Aktif',   'Video şema kapalı',                   5);

        // Technical SEO
        $checks[] = $this->check('sitemap',          $hasSitemap,                          'Sitemap Mevcut',                     'sitemap.xml bulunamadı',              8);
        $checks[] = $this->check('robots_exists',    !empty($robots),                      'robots.txt Mevcut',                  'robots.txt yok veya boş',             6);
        $checks[] = $this->check('robots_admin',     str_contains($robots, 'Disallow: /admin'), 'robots.txt Admin Kapalı',       'robots.txt /admin dizini kapalı değil', 6);
        $checks[] = $this->check('noindex_search',   ($seo['seo_noindex_search'] ?? '1') === '1', 'Arama Sayfası Noindex',      'Arama sayfası indexleniyor',          5);
        $checks[] = $this->check('twitter',          !empty($seo['seo_twitter_site']),     'Twitter Card Yapılandırıldı',        'Twitter hesabı girilmemiş',           4);
        $checks[] = $this->check('bing',             !empty($seo['seo_bing_verification']), 'Bing Webmaster Doğrulandı',         'Bing doğrulama kodu eksik',           3);

        // Content quality
        $checks[] = $this->check('anime_desc',       $noDesc === 0,                        'Tüm Animelerin Açıklaması Var',      "{$noDesc} animenin açıklaması eksik", 8);
        $checks[] = $this->check('anime_cover',      $noCover === 0,                       'Tüm Animelerin Kapağı Var',          "{$noCover} animenin görseli eksik",   7);
        $checks[] = $this->check('desc_quality',     $shortDesc < max(1, $total * 0.1),    'Açıklama Kalitesi İyi',              "{$shortDesc} animenin açıklaması çok kısa", 4);
        $checks[] = $this->check('slug_coverage',    $noSlug === 0,                        'Tüm Animeler URL Slug\'a Sahip',     "{$noSlug} animenin slug\'u eksik",    6);
        $checks[] = $this->check('seo_titles',       $noSeoTitle < $total * 0.2,           'Anime SEO Başlıkları Yeterli',       "{$noSeoTitle} animenin SEO başlığı eksik", 6);
        $checks[] = $this->check('dup_desc',         $dupDesc === 0,                       'Tekrarlayan İçerik Yok',             "{$dupDesc} grup tekrarlayan açıklama var", 5);

        $score = $weight = 0;
        foreach ($checks as $c) {
            $weight += $c['weight'];
            if ($c['pass']) $score += $c['weight'];
        }

        $scorePercent = $weight > 0 ? round(($score / $weight) * 100) : 0;

        return [
            'score'      => $scorePercent,
            'checks'     => $checks,
            'totals'     => ['total' => $total, 'noDesc' => $noDesc, 'noCover' => $noCover, 'shortDesc' => $shortDesc, 'noSeoTitle' => $noSeoTitle, 'dupDesc' => $dupDesc],
            'pass_count' => collect($checks)->where('pass', true)->count(),
            'fail_count' => collect($checks)->where('pass', false)->count(),
        ];
    }

    private function check(string $id, bool $pass, string $passMsg, string $failMsg, int $weight): array
    {
        return compact('id', 'pass', 'passMsg', 'failMsg', 'weight');
    }
}
