<?php

namespace Kanews\Kai\Feeds;

use Kanews\Kai\Manager;
use Kanews\Kai\Support\Credits;
use Kanews\Kai\Support\ImageHelper;
use Kanews\Kai\Support\Options;

class FeedManager
{
    private $manager;
    private const STATE_OPTION = 'kanews_kai_feed_state';
    private const CRON_HOOK = 'kanews_kai_news_feed_cron';

    public function __construct(Manager $manager)
    {
        $this->manager = $manager;
    }

    public function register(): void
    {
        add_action('init', function() {
            $this->maybeScheduleCron();
        });
        add_action(self::CRON_HOOK, [$this, 'runScheduledFeeds']);
        add_action('switch_theme', [$this, 'clearSchedule']);
        add_filter('cron_schedules', [$this, 'addCustomSchedules']);

        // Admin handlers
        add_action('admin_post_kanews_add_kai_feed', [$this, 'handleAddFeed']);
        add_action('admin_post_kanews_toggle_kai_feed', [$this, 'handleToggleFeed']);
        add_action('admin_post_kanews_delete_kai_feed', [$this, 'handleDeleteFeed']);
        add_action('admin_post_kanews_run_kai_feed', [$this, 'handleRunFeed']);
        add_action('admin_post_kanews_edit_kai_feed', [$this, 'handleEditFeed']);
    }

    public function getState(): array
    {
        $default = [
            'feeds' => [],
            'settings' => ['interval' => 'hourly'],
        ];

        $state = get_option(self::STATE_OPTION, $default);
        if (!is_array($state)) {
            $state = $default;
        }

        return array_merge($default, $state);
    }

    public function saveState(array $state): void
    {
        update_option(self::STATE_OPTION, $state, false);
        $this->maybeScheduleCron($state);
    }

    public function processFeeds(?string $targetFeedId = null, bool $manual = false): array
    {
        $state = $this->getState();
        $processed = 0;
        $importedTotal = 0;
        $errors = [];
        $found = false;
        $timestamp = current_time('timestamp');

        foreach ($state['feeds'] as &$feed) {
            if ($targetFeedId && ($feed['id'] ?? '') !== $targetFeedId) {
                continue;
            }

            $found = true;

            if (!$manual && empty($feed['active'])) {
                continue;
            }

            // Provider credential guard: disable and skip if model's provider key is missing.
            $provider = $this->providerForModel($feed['model'] ?? '');
            if (!$this->providerHasCredentials($provider)) {
                $feed['active'] = false;
                $feed['last_run'] = $timestamp;
                $feed['last_post_count'] = 0;
                $feed['last_error'] = sprintf(
                    __('Seçilen model için %s API anahtarı bulunamadı. Görev durduruldu.', 'kanews'),
                    $provider === 'gemini' ? 'Gemini' : 'OpenAI'
                );
                $feed['stats'] = [
                    'imported' => 0,
                    'skipped' => 0,
                    'timestamp' => $timestamp,
                ];
                $errors[] = sprintf(
                    '%s: %s',
                    $feed['title'] ?: ($feed['url'] ?? ''),
                    $feed['last_error']
                );
                continue;
            }

            $processed++;
            $result = $this->handleSingleFeed($feed);

            $feed['last_run'] = $timestamp;
            $feed['last_post_count'] = $result['imported'];
            $feed['last_error'] = $result['error'];
            $feed['stats'] = [
                'imported' => $result['imported'],
                'skipped' => $result['skipped'],
                'timestamp' => $timestamp,
            ];

            $importedTotal += $result['imported'];

            if (!empty($result['error'])) {
                $errors[] = sprintf('%s: %s', $feed['title'] ?: $feed['url'], $result['error']);
            }
        }
        unset($feed);

        $this->saveState($state);

        if ($targetFeedId && !$found) {
            return [
                'processed' => 0,
                'imported' => 0,
                'errors' => [__('Feed bulunamadı.', 'kanews')],
                'success' => false,
            ];
        }

        return [
            'processed' => $processed,
            'imported' => $importedTotal,
            'errors' => $errors,
            'success' => empty($errors),
        ];
    }

    private function providerForModel(string $model): string
    {
        $model = strtolower($model);
        if (strpos($model, 'gemini') === 0) {
            return 'gemini';
        }
        return 'openai';
    }

    private function providerHasCredentials(string $provider): bool
    {
        if ($provider === 'gemini') {
            return !empty(Options::getApiKey('gemini'));
        }
        // default openai
        return !empty(Options::getApiKey('openai'));
    }

    private function handleSingleFeed(array &$feed): array
    {
        $maxItems = max(1, min(10, (int) ($feed['max_items'] ?? 3)));
        $imported = 0;
        $skipped = 0;
        $errors = [];

        if (!function_exists('fetch_feed')) {
            include_once ABSPATH . WPINC . '/feed.php';
        }

        $feedData = fetch_feed($feed['url']);
        if (is_wp_error($feedData)) {
            return [
                'imported' => 0,
                'skipped' => 0,
                'error' => $feedData->get_error_message(),
            ];
        }

        $items = $feedData->get_items(0, $maxItems);
        if (empty($items)) {
            return [
                'imported' => 0,
                'skipped' => 0,
                'error' => __('Feed içerisinde yeni içerik bulunamadı.', 'kanews'),
            ];
        }

        foreach ($items as $item) {
            $permalink = $item->get_permalink();
            if (empty($permalink)) {
                $skipped++;
                continue;
            }

            $hash = md5($feed['id'] . '|' . $permalink);
            if ($this->sourceExists($hash)) {
                $skipped++;
                continue;
            }

            $rawContent = $item->get_content();
            $textLength = mb_strlen(wp_strip_all_tags($rawContent ?? ''));

            if ($textLength < 200) {
                $fetched = $this->fetchArticleContent($permalink);
                if (!empty($fetched)) {
                    $rawContent = $fetched;
                }
            }

            if (empty(trim(wp_strip_all_tags($rawContent ?? '')))) {
                $skipped++;
                continue;
            }

            $preparedContent = $this->truncateInput($rawContent);
            $wordCount = str_word_count(wp_strip_all_tags($preparedContent));

            if (!Credits::reduce(max(1, ceil($wordCount / 100)))) {
                $errors[] = __('Yeterli KAI kredisi bulunamadı.', 'kanews');
                break;
            }

            $rewrite = $this->generateRewrittenArticle($item->get_title(), $preparedContent, $permalink, $feed);

            if (!$rewrite) {
                $errors[] = sprintf(
                    __('"%s" içeriği özgünleştirilemedi.', 'kanews'),
                    $item->get_title()
                );
                continue;
            }

            $postTitle = !empty($rewrite['title']) ? $rewrite['title'] : $item->get_title();
            $postContent = trim($rewrite['content']);

            if (empty($postContent)) {
                $errors[] = sprintf(
                    __('"%s" içeriği boş döndü.', 'kanews'),
                    $postTitle
                );
                continue;
            }

            $postAuthor = !empty($feed['post_author']) ? (int) $feed['post_author'] : get_current_user_id();

            $postId = wp_insert_post([
                'post_title'   => wp_strip_all_tags($postTitle),
                'post_content' => wp_kses_post($postContent),
                'post_status'  => $feed['post_status'] ?? 'publish',
                'post_author'  => $postAuthor,
            ], true);

            if (is_wp_error($postId)) {
                $errors[] = $postId->get_error_message();
                continue;
            }

            // Mark post as created by this feed
            if (!empty($feed['id'])) {
                update_post_meta($postId, '_kai_feed_id', $feed['id']);
            }
            update_post_meta($postId, '_kai_source_url', esc_url_raw($permalink));

            // Assign category if suggested
            if (!empty($rewrite['category_slug'])) {
                $term = get_term_by('slug', sanitize_title($rewrite['category_slug']), 'category');
                if ($term && !is_wp_error($term)) {
                    wp_set_post_terms($postId, [(int) $term->term_id], 'category', false);
                }
            }

            // Generate excerpt
            $excerptText = '';
            if (Credits::reduce(Credits::calculateFromContent($postContent))) {
                $excerptResp = $this->manager->ai()->chat('excerpt', [
                    'text' => wp_strip_all_tags(strip_shortcodes($postContent)),
                ]);
                if ($excerptResp && isset($excerptResp['content'])) {
                    $excerptText = trim($excerptResp['content']);
                }
            }
            if (empty($excerptText)) {
                $excerptText = wp_trim_words(wp_strip_all_tags($postContent), 30, '...');
            }
            if (!empty($excerptText)) {
                wp_update_post([
                    'ID' => $postId,
                    'post_excerpt' => $excerptText,
                ]);
            }

            $preferredImageSource = $this->normalizeImageSource($feed['image_source'] ?? '');
            $imageSource = $this->resolveFeedImageSource($feed);
            if (empty($feed['image_source'])) {
                $feed['image_source'] = $imageSource;
            }
            if ($preferredImageSource && $preferredImageSource !== $imageSource) {
                $errors[] = sprintf(
                    __('Seçilen görsel kaynağı "%1$s" kullanılamadı, "%2$s" ile devam edildi.', 'kanews'),
                    $this->imageSourceLabel($preferredImageSource),
                    $this->imageSourceLabel($imageSource)
                );
            }

            switch ($imageSource) {
                case 'none':
                    break;

                case 'pexels':
                    $images = ImageHelper::fetchPexelsImages($postTitle);
                    if (is_array($images) && !empty($images)) {
                        $imageId = ImageHelper::uploadFeaturedImage($images[0], $postId);
                        if (!$imageId || is_wp_error($imageId)) {
                            $errors[] = __('Pexels görseli yazıya eklenemedi.', 'kanews');
                        }
                    } else {
                        $errors[] = __('Pexels görseli bulunamadı.', 'kanews');
                    }
                    break;

                case 'gemini':
                case 'openai':
                    $prompt = sprintf(
                        'Ultra-realistic editorial news photograph of: %s. Shot on professional DSLR with 35mm lens, shallow depth of field, accurate skin tones and textures, natural lighting, true-to-life colors, photojournalism style. No illustrations, no CGI, no painting, no cartoons, no overlays, no text, no watermarks, no logos.',
                        $postTitle
                    );
                    $bytes = $imageSource === 'gemini'
                        ? ImageHelper::geminiImage($prompt)
                        : ImageHelper::dalleImage($prompt, '1024x1024');

                    if (is_wp_error($bytes)) {
                        $errors[] = $imageSource === 'gemini'
                            ? sprintf(__('Gemini görsel hatası: %s', 'kanews'), $bytes->get_error_message())
                            : sprintf(__('OpenAI görsel hatası: %s', 'kanews'), $bytes->get_error_message());

                        if ($imageSource === 'gemini' && $this->isImageSourceUsable('openai')) {
                            $fallbackBytes = ImageHelper::dalleImage($prompt, '1024x1024');
                            if ($fallbackBytes) {
                                $bytes = $fallbackBytes;
                                $errors[] = __('OpenAI DALL·E ile yedek görsel üretildi.', 'kanews');
                            } else {
                                $bytes = null;
                            }
                        } else {
                            $bytes = null;
                        }
                    } elseif (!$bytes) {
                        $errors[] = $imageSource === 'gemini'
                            ? __('Gemini görsel yanıtı boş döndü.', 'kanews')
                            : __('OpenAI görsel yanıtı boş döndü.', 'kanews');
                    }

                    if (!empty($bytes) && !is_wp_error($bytes)) {
                        $suffix = $imageSource === 'gemini' ? 'gemini' : 'dalle3';
                        $imageId = ImageHelper::uploadFeaturedImageFromBytes(
                            $bytes,
                            $postId,
                            sanitize_file_name($postTitle) . '-' . $suffix . '.jpg'
                        );
                        if (!$imageId || is_wp_error($imageId)) {
                            $errors[] = __('Üretilen görsel yazıya eklenemedi.', 'kanews');
                        }
                    }
                    break;
            }

            update_post_meta($postId, '_kai_source_hash', $hash);
            $imported++;
        }

        return [
            'imported' => $imported,
            'skipped' => $skipped,
            'error' => empty($errors) ? '' : implode(' | ', array_unique($errors)),
        ];
    }

    private function generateRewrittenArticle(string $title, string $content, string $sourceUrl, array $feed): array
    {
        $flags = [
            'use_5w1h'   => !empty($feed['use_5w1h']),
            'add_faq'    => !empty($feed['add_faq']),
            'use_tables' => !empty($feed['use_tables']),
            'use_list'   => !empty($feed['use_list']),
        ];

        $model = $feed['model'] ?? 'gpt-4o-mini';
        $provider = $this->providerForModel($model);

        $response = $this->manager->ai()->chat('news-bot', [
            'title'      => $title,
            'source_url' => $sourceUrl,
            'model'      => $model,
            'provider'   => $provider,
            'flags'      => $flags,
            'categories' => $this->buildCategoryChoices(),
        ]);

        if (!$response || !isset($response['content'])) {
            return [];
        }

        $raw = trim($response['content']);
        $lines = preg_split("/\r\n|\n|\r/", $raw);
        $headline = '';
        $categorySlug = '';

        if (!empty($lines) && stripos($lines[0], 'TITLE:') === 0) {
            $headline = trim(substr($lines[0], strlen('TITLE:')));
            array_shift($lines);
            if (!empty($lines) && trim($lines[0]) === '') {
                array_shift($lines);
            }
        }

        // Extract CATEGORY line
        for ($i = count($lines) - 1; $i >= 0; $i--) {
            $line = trim($lines[$i]);
            if (stripos($line, 'CATEGORY:') === 0) {
                $categorySlug = trim(substr($line, strlen('CATEGORY:')));
                unset($lines[$i]);
                break;
            }
        }

        $body = trim(implode("\n", $lines));
        if (empty($body)) {
            $body = $raw;
        }

        return [
            'title' => $headline,
            'content' => $body,
            'category_slug' => $categorySlug,
        ];
    }

    private function fetchArticleContent(string $url): string
    {
        $response = wp_remote_get($url, [
            'timeout' => 20,
            'redirection' => 5,
            'headers' => [
                'User-Agent' => 'KAI Bot/1.0; ' . home_url('/'),
            ],
        ]);

        if (is_wp_error($response)) {
            return '';
        }

        $rawBody = wp_remote_retrieve_body($response);
        if (empty($rawBody)) {
            return '';
        }

        $content = $this->extractMainContent($rawBody);
        if (empty($content)) {
            $content = wp_strip_all_tags($rawBody);
        }

        return trim($content);
    }

    private function extractMainContent(string $html): string
    {
        if (empty($html)) {
            return '';
        }

        libxml_use_internal_errors(true);
        $doc = new \DOMDocument();
        $encoded = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8');

        if (!@$doc->loadHTML($encoded)) {
            libxml_clear_errors();
            return '';
        }
        libxml_clear_errors();

        $xpath = new \DOMXPath($doc);
        $selectors = [
            '//article',
            '//*[@id="content"]',
            '//*[@id="main"]',
            '//*[contains(@class,"article")]',
            '//*[contains(@class,"content")]',
            '//*[contains(@class,"entry")]',
            '//*[contains(@class,"post")]',
        ];

        $bestNode = null;
        $bestScore = 0;

        foreach ($selectors as $selector) {
            $nodes = $xpath->query($selector);
            if (!$nodes) {
                continue;
            }
            foreach ($nodes as $node) {
                $length = mb_strlen(trim($node->textContent));
                if ($length > $bestScore) {
                    $bestScore = $length;
                    $bestNode = $node;
                }
            }
            if ($bestScore > 1500) {
                break;
            }
        }

        if (!$bestNode) {
            $bodyNodes = $xpath->query('//body');
            if ($bodyNodes && $bodyNodes->length) {
                $bestNode = $bodyNodes->item(0);
            }
        }

        if (!$bestNode) {
            return '';
        }

        $content = $this->domInnerHtml($bestNode);
        $content = preg_replace('#<(script|style|noscript)[^>]*>.*?</\1>#is', '', $content);

        return trim($content);
    }

    private function domInnerHtml(\DOMNode $node): string
    {
        $html = '';
        foreach ($node->childNodes as $child) {
            $html .= $node->ownerDocument->saveHTML($child);
        }
        return $html;
    }

    private function truncateInput(string $content, int $limit = 12000): string
    {
        $content = trim($content);
        if (function_exists('mb_strlen') && mb_strlen($content) > $limit) {
            return mb_substr($content, 0, $limit);
        }
        if (strlen($content) > $limit) {
            return substr($content, 0, $limit);
        }
        return $content;
    }

    private function sourceExists(string $hash): bool
    {
        if (empty($hash)) {
            return false;
        }

        $existing = get_posts([
            'post_type' => 'post',
            'post_status' => 'any',
            'meta_key' => '_kai_source_hash',
            'meta_value' => $hash,
            'fields' => 'ids',
            'posts_per_page' => 1,
            'no_found_rows' => true,
            'cache_results' => false,
        ]);

        return !empty($existing);
    }

    public function maybeScheduleCron($state = null): void
    {
        // WordPress hooks may pass unexpected parameters, so we validate
        if (!is_array($state) && $state !== null) {
            $state = null;
        }
        
        if (null === $state) {
            $state = $this->getState();
        }

        $hasActive = false;
        foreach ($state['feeds'] as $feed) {
            if (!empty($feed['active'])) {
                $hasActive = true;
                break;
            }
        }

        $next = wp_next_scheduled(self::CRON_HOOK);

        if ($hasActive) {
            $interval = $state['settings']['interval'] ?? 'hourly';
            if (!$next) {
                wp_schedule_event(time() + MINUTE_IN_SECONDS, $interval, self::CRON_HOOK);
            } else {
                $scheduled = wp_get_schedule(self::CRON_HOOK);
                if ($scheduled !== $interval) {
                    wp_unschedule_event($next, self::CRON_HOOK);
                    wp_schedule_event(time() + MINUTE_IN_SECONDS, $interval, self::CRON_HOOK);
                }
            }
        } elseif ($next) {
            wp_unschedule_event($next, self::CRON_HOOK);
        }
    }

    public function runScheduledFeeds(): void
    {
        $this->processFeeds(null, false);
    }

    public function clearSchedule(): void
    {
        $timestamp = wp_next_scheduled(self::CRON_HOOK);
        if ($timestamp) {
            wp_unschedule_event($timestamp, self::CRON_HOOK);
        }
    }

    public function addCustomSchedules(array $schedules): array
    {
        if (!isset($schedules['quarterhourly'])) {
            $schedules['quarterhourly'] = [
                'interval' => 15 * MINUTE_IN_SECONDS,
                'display' => __('Her 15 dakikada bir', 'kanews'),
            ];
        }
        if (!isset($schedules['half-hourly'])) {
            $schedules['half-hourly'] = [
                'interval' => 30 * MINUTE_IN_SECONDS,
                'display' => __('Her 30 dakikada bir', 'kanews'),
            ];
        }
        return $schedules;
    }

    // Admin handlers
    public function handleAddFeed(): void
    {
        if (!current_user_can('manage_options')) {
            wp_die(__('Bu işlem için yetkiniz yok.', 'kanews'));
        }

        check_admin_referer('kanews_add_kai_feed');

        $title = sanitize_text_field($_POST['feed_title'] ?? '');
        $feedUrl = isset($_POST['feed_url']) ? esc_url_raw(trim($_POST['feed_url'])) : '';
        $maxItems = isset($_POST['feed_max_items']) ? max(1, min(10, absint($_POST['feed_max_items']))) : 3;
        $postStatus = isset($_POST['feed_post_status']) && in_array($_POST['feed_post_status'], ['publish', 'draft', 'pending'], true)
            ? $_POST['feed_post_status']
            : 'publish';
        $postAuthor = isset($_POST['feed_author']) ? absint($_POST['feed_author']) : get_current_user_id();
        $isActive = !empty($_POST['feed_active']);
        $imageSource = $this->sanitizeFeedImageSource($_POST['feed_image_source'] ?? '');
        $aiModel = $this->sanitizeFeedAiModel($_POST['feed_ai_model'] ?? '');

        if (empty($feedUrl)) {
            $this->addNotice('error', __('Feed adresi zorunludur.', 'kanews'));
            wp_safe_redirect(admin_url('admin.php?page=kanews-kai'));
            exit;
        }

        $state = $this->getState();

        foreach ($state['feeds'] as $feed) {
            if (!empty($feed['url']) && $feed['url'] === $feedUrl) {
                $this->addNotice('error', __('Bu feed zaten eklenmiş.', 'kanews'));
                wp_safe_redirect(admin_url('admin.php?page=kanews-kai'));
                exit;
            }
        }

        if (!function_exists('fetch_feed')) {
            include_once ABSPATH . WPINC . '/feed.php';
        }

        $detectedTitle = $title;
        if (empty($detectedTitle)) {
            $feedData = fetch_feed($feedUrl);
            if (!is_wp_error($feedData)) {
                $detectedTitle = trim($feedData->get_title());
            }
        }

        $state['feeds'][] = [
            'id' => uniqid('kai_', true),
            'title' => $detectedTitle,
            'url' => $feedUrl,
            'active' => $isActive,
            'max_items' => $maxItems,
            'post_status' => $postStatus,
            'post_author' => $postAuthor,
            'use_5w1h' => !empty($_POST['feed_use_5w1h']),
            'add_faq' => !empty($_POST['feed_add_faq']),
            'use_tables' => !empty($_POST['feed_use_tables']),
            'use_list' => !empty($_POST['feed_use_list']),
            'image_source' => $imageSource,
            'model' => $aiModel,
            'last_run' => null,
            'last_error' => '',
            'last_post_count' => 0,
            'stats' => [],
            'created_at' => current_time('timestamp'),
        ];

        $this->saveState($state);
        $this->addNotice('success', __('Feed başarıyla eklendi.', 'kanews'));
        wp_safe_redirect(admin_url('admin.php?page=kanews-kai'));
        exit;
    }
    public function handleEditFeed(): void
    {
        if (!current_user_can('manage_options')) {
            wp_die(__('Bu işlem için yetkiniz yok.', 'kanews'));
        }

        $feedId = isset($_POST['feed_id']) ? sanitize_text_field(wp_unslash($_POST['feed_id'])) : '';
        if (empty($feedId)) {
            $this->addNotice('error', __('Feed bulunamadı.', 'kanews'));
            wp_safe_redirect(admin_url('admin.php?page=kanews-kai'));
            exit;
        }

        check_admin_referer('kanews_edit_kai_feed_' . $feedId);

        $title = sanitize_text_field($_POST['feed_title'] ?? '');
        $feedUrl = isset($_POST['feed_url']) ? esc_url_raw(trim($_POST['feed_url'])) : '';
        $maxItems = isset($_POST['feed_max_items']) ? max(1, min(10, absint($_POST['feed_max_items']))) : 3;
        $postStatus = isset($_POST['feed_post_status']) && in_array($_POST['feed_post_status'], ['publish', 'draft', 'pending'], true)
            ? $_POST['feed_post_status']
            : 'publish';
        $postAuthor = isset($_POST['feed_author']) ? absint($_POST['feed_author']) : get_current_user_id();
        $isActive = !empty($_POST['feed_active']);
        $imageSource = $this->sanitizeFeedImageSource($_POST['feed_image_source'] ?? '');
        $aiModel = $this->sanitizeFeedAiModel($_POST['feed_ai_model'] ?? '');

        if (empty($feedUrl)) {
            $this->addNotice('error', __('Feed adresi zorunludur.', 'kanews'));
            wp_safe_redirect(admin_url('admin.php?page=kanews-kai&edit_feed=' . rawurlencode($feedId) . '#kai-feeds'));
            exit;
        }

        $state = $this->getState();
        $duplicate = false;
        foreach ($state['feeds'] as $feed) {
            if (($feed['id'] ?? '') !== $feedId && !empty($feed['url']) && $feed['url'] === $feedUrl) {
                $duplicate = true;
                break;
            }
        }
        if ($duplicate) {
            $this->addNotice('error', __('Bu feed adresi başka bir kayıtla eşleşiyor.', 'kanews'));
            wp_safe_redirect(admin_url('admin.php?page=kanews-kai&edit_feed=' . rawurlencode($feedId) . '#kai-feeds'));
            exit;
        }

        $updated = false;
        foreach ($state['feeds'] as &$feed) {
            if (($feed['id'] ?? '') === $feedId) {
                $feed['title'] = $title;
                $feed['url'] = $feedUrl;
                $feed['max_items'] = $maxItems;
                $feed['post_status'] = $postStatus;
                $feed['post_author'] = $postAuthor;
                $feed['active'] = $isActive;
                $feed['use_5w1h'] = !empty($_POST['feed_use_5w1h']);
                $feed['add_faq'] = !empty($_POST['feed_add_faq']);
                $feed['use_tables'] = !empty($_POST['feed_use_tables']);
                $feed['use_list'] = !empty($_POST['feed_use_list']);
                $feed['image_source'] = $imageSource;
                $feed['model'] = $aiModel;
                $updated = true;
                break;
            }
        }
        unset($feed);

        if (!$updated) {
            $this->addNotice('error', __('Feed bulunamadı.', 'kanews'));
            wp_safe_redirect(admin_url('admin.php?page=kanews-kai'));
            exit;
        }

        $this->saveState($state);
        $this->addNotice('success', __('Feed güncellendi.', 'kanews'));
        wp_safe_redirect(admin_url('admin.php?page=kanews-kai#kai-feeds'));
        exit;
    }

    public function availableImageSources(): array
    {
        $options = [
            'none' => __('Görsel oluşturma', 'kanews'),
        ];

        foreach (['openai', 'gemini', 'pexels'] as $candidate) {
            if ($this->isImageSourceUsable($candidate)) {
                $options[$candidate] = $this->imageSourceLabel($candidate);
            }
        }

        return $options;
    }

    public function imageSourceLabels(): array
    {
        return [
            'none'   => __('Görsel oluşturma', 'kanews'),
            'openai' => __('OpenAI DALL·E 3', 'kanews'),
            'gemini' => __('Google Gemini 2.5 Flash Image', 'kanews'),
            'pexels' => __('Pexels Stok Fotoğraf', 'kanews'),
        ];
    }

    public function imageSourceLabel(string $source): string
    {
        $labels = $this->imageSourceLabels();
        $normalized = $this->normalizeImageSource($source) ?: 'none';
        return $labels[$normalized] ?? ucfirst($normalized);
    }

    public function defaultImageSource(): string
    {
        foreach (['openai', 'gemini', 'pexels'] as $candidate) {
            if ($this->isImageSourceUsable($candidate)) {
                return $candidate;
            }
        }

        return 'none';
    }

    public function availableAiModels(): array
    {
        $options = [];
        if (!empty(Options::getApiKey('openai'))) {
            $options += [
                'gpt-4o-mini' => __('OpenAI · GPT-4o Mini', 'kanews'),
                'gpt-4o'      => __('OpenAI · GPT-4o', 'kanews'),
                'gpt-4-turbo' => __('OpenAI · GPT-4 Turbo', 'kanews'),
            ];
        }
        if (!empty(Options::getApiKey('gemini'))) {
            $options += [
                'gemini-2.0-flash' => __('Gemini · 2.0 Flash', 'kanews'),
                'gemini-1.5-flash' => __('Gemini · 1.5 Flash', 'kanews'),
            ];
        }

        if (empty($options)) {
            $options = [
                'gpt-4o-mini' => __('OpenAI · GPT-4o Mini', 'kanews'),
            ];
        }

        return $options;
    }

    public function defaultAiModel(): string
    {
        $models = $this->availableAiModels();
        return key($models);
    }

    public function aiModelLabel(string $model): string
    {
        $models = $this->availableAiModels();
        return $models[$model] ?? $model;
    }

    private function sanitizeFeedImageSource(?string $value): string
    {
        $normalized = $this->normalizeImageSource($value ?? '');
        if ($normalized === 'none') {
            return 'none';
        }

        if ($this->isImageSourceUsable($normalized)) {
            return $normalized;
        }

        return $this->defaultImageSource();
    }

    private function sanitizeFeedAiModel(?string $value): string
    {
        $model = (string) $value;
        $available = $this->availableAiModels();
        if (isset($available[$model])) {
            return $model;
        }

        return $this->defaultAiModel();
    }

    private function resolveFeedImageSource(array $feed): string
    {
        $preferred = $this->normalizeImageSource($feed['image_source'] ?? '');
        if ($preferred && $this->isImageSourceUsable($preferred)) {
            return $preferred;
        }

        return $this->defaultImageSource();
    }

    private function normalizeImageSource(?string $value): string
    {
        $normalized = strtolower((string) $value);
        if ($normalized === 'ai') {
            return 'openai';
        }

        return $normalized;
    }

    private function isImageSourceUsable(string $source): bool
    {
        $normalized = $this->normalizeImageSource($source);

        switch ($normalized) {
            case 'openai':
                return !empty(Options::getApiKey('openai'));
            case 'gemini':
                return !empty(Options::getApiKey('gemini'));
            case 'pexels':
                return !empty(Options::getApiKey('pexels'));
            case 'none':
                return true;
            default:
                return false;
        }
    }

    /**
     * Build a comma-separated list of existing WordPress category slugs
     * for the news-bot prompt (e.g. "gundem, ekonomi, spor").
     */
    private function buildCategoryChoices(): string
    {
        $terms = get_categories([
            'hide_empty' => false,
        ]);

        if (empty($terms) || !is_array($terms)) {
            return '';
        }

        $slugs = [];
        foreach ($terms as $term) {
            if (!empty($term->slug)) {
                $slugs[] = $term->slug;
            }
        }

        return implode(', ', array_unique($slugs));
    }

    public function handleToggleFeed(): void
    {
        if (!current_user_can('manage_options')) {
            wp_die(__('Bu işlem için yetkiniz yok.', 'kanews'));
        }

        $feedId = isset($_GET['feed_id']) ? sanitize_text_field(wp_unslash($_GET['feed_id'])) : '';
        $state = isset($_GET['state']) ? sanitize_text_field(wp_unslash($_GET['state'])) : '0';

        if (empty($feedId)) {
            $this->addNotice('error', __('Feed bulunamadı.', 'kanews'));
            wp_safe_redirect(admin_url('admin.php?page=kanews-kai'));
            exit;
        }

        check_admin_referer('kanews_toggle_kai_feed_' . $feedId);

        $feeds = $this->getState();
        $updated = false;

        foreach ($feeds['feeds'] as &$feed) {
            if (($feed['id'] ?? '') === $feedId) {
                $feed['active'] = $state === '1';
                $updated = true;
                break;
            }
        }
        unset($feed);

        if (!$updated) {
            $this->addNotice('error', __('Feed bulunamadı.', 'kanews'));
            wp_safe_redirect(admin_url('admin.php?page=kanews-kai'));
            exit;
        }

        $this->saveState($feeds);
        $this->addNotice('success', $state === '1' ? __('Feed aktifleştirildi.', 'kanews') : __('Feed durduruldu.', 'kanews'));

        wp_safe_redirect(admin_url('admin.php?page=kanews-kai'));
        exit;
    }

    public function handleDeleteFeed(): void
    {
        if (!current_user_can('manage_options')) {
            wp_die(__('Bu işlem için yetkiniz yok.', 'kanews'));
        }

        $feedId = isset($_GET['feed_id']) ? sanitize_text_field(wp_unslash($_GET['feed_id'])) : '';
        if (empty($feedId)) {
            $this->addNotice('error', __('Feed bulunamadı.', 'kanews'));
            wp_safe_redirect(admin_url('admin.php?page=kanews-kai'));
            exit;
        }

        check_admin_referer('kanews_delete_kai_feed_' . $feedId);

        $state = $this->getState();
        $origCount = count($state['feeds']);
        $state['feeds'] = array_values(array_filter($state['feeds'], function ($feed) use ($feedId) {
            return ($feed['id'] ?? '') !== $feedId;
        }));

        if ($origCount === count($state['feeds'])) {
            $this->addNotice('error', __('Feed bulunamadı.', 'kanews'));
            wp_safe_redirect(admin_url('admin.php?page=kanews-kai'));
            exit;
        }

        $this->saveState($state);
        $this->addNotice('success', __('Feed silindi.', 'kanews'));

        wp_safe_redirect(admin_url('admin.php?page=kanews-kai'));
        exit;
    }

    public function handleRunFeed(): void
    {
        if (!current_user_can('manage_options')) {
            wp_die(__('Bu işlem için yetkiniz yok.', 'kanews'));
        }

        $feedId = isset($_GET['feed_id']) ? sanitize_text_field(wp_unslash($_GET['feed_id'])) : '';
        if (empty($feedId)) {
            $this->addNotice('error', __('Feed bulunamadı.', 'kanews'));
            wp_safe_redirect(admin_url('admin.php?page=kanews-kai'));
            exit;
        }

        check_admin_referer('kanews_run_kai_feed_' . $feedId);

        $result = $this->processFeeds($feedId, true);

        if (!empty($result['errors'])) {
            $this->addNotice('error', implode(' | ', $result['errors']));
        } else {
            $this->addNotice('success', sprintf(__('%d yeni yazı oluşturuldu.', 'kanews'), (int) $result['imported']));
        }

        wp_safe_redirect(admin_url('admin.php?page=kanews-kai'));
        exit;
    }

    private function addNotice(string $type, string $message): void
    {
        set_transient('kanews_kai_notice', [
            'type' => $type,
            'message' => $message,
        ], 45);
    }
}

