<?php

if (!defined('ABSPATH')) {
    exit;
}

class SEO_Fury_General {

    public function __construct() {
        $this->init_hooks();
    }

private function init_hooks() {
    // Priority 9 = run BEFORE WP core sanitize_title_with_dashes (priority 10)
    // which strips all non-ASCII characters. We convert Cyrillic → Latin first.
    add_filter('sanitize_title', array($this, 'transliterate_slug'), 9, 3);

    // Gutenberg / REST API: intercept slug before post is inserted into DB.
    add_filter('wp_insert_post_data', array($this, 'transliterate_on_insert'), 10, 2);

    // Catch slug right before uniqueness check (covers every save path).
    add_filter('wp_unique_post_slug', array($this, 'transliterate_unique_slug'), 10, 6);

    // Final safety net: fix slug AFTER post is saved (catches draft→publish transitions
    // and any case where slug was auto-generated as garbage like "chernovik" / ID).
    add_action('wp_insert_post', array($this, 'fix_slug_after_save'), 10, 3);

    // Transliterate Cyrillic filenames on media upload (before WP sanitize)
    add_filter('sanitize_file_name', array($this, 'transliterate_filename'), 5);

    add_action('wp_ajax_seo_bulk_transliterate', array($this, 'ajax_bulk_transliterate'));
    add_action('wp_ajax_seo_get_url_stats', array($this, 'ajax_get_url_stats'));

    add_action('template_redirect', array($this, 'handle_security_redirects'), 1);
    add_action('send_headers', array($this, 'send_security_headers'));

    if (get_option('seo_fury_fix_mixed_content', 0) && !is_admin()) {
        add_action('template_redirect', array($this, 'start_mixed_content_buffer'), 2);
    }
}

public function register_settings() {
    register_setting('seo_fury_general_settings', 'seo_fury_transliterate_urls', array(
        'type' => 'boolean',
        'default' => 1,
        'sanitize_callback' => array($this, 'sanitize_checkbox')
    ));

    register_setting('seo_fury_ssl_settings', 'seo_fury_force_https', array('type' => 'boolean', 'default' => 0, 'sanitize_callback' => array($this, 'sanitize_checkbox')));
    register_setting('seo_fury_ssl_settings', 'seo_fury_fix_mixed_content', array('type' => 'boolean', 'default' => 0, 'sanitize_callback' => array($this, 'sanitize_checkbox')));
    register_setting('seo_fury_ssl_settings', 'seo_fury_enable_hsts', array('type' => 'boolean', 'default' => 0, 'sanitize_callback' => array($this, 'sanitize_checkbox')));
    register_setting('seo_fury_ssl_settings', 'seo_fury_hsts_max_age', array('type' => 'integer', 'default' => 31536000, 'sanitize_callback' => 'absint'));
    register_setting('seo_fury_ssl_settings', 'seo_fury_www_redirect', array('type' => 'string', 'default' => '', 'sanitize_callback' => 'sanitize_text_field'));

    register_setting('seo_fury_general_settings', 'seo_fury_plugin_language', array(
        'type' => 'string',
        'default' => '',
        'sanitize_callback' => 'sanitize_text_field'
    ));

    register_setting('seo_fury_general_settings', 'seo_fury_white_label_enabled', array('sanitize_callback' => 'absint'));
    register_setting('seo_fury_general_settings', 'seo_fury_white_label_name', array('sanitize_callback' => 'sanitize_text_field'));
    register_setting('seo_fury_general_settings', 'seo_fury_white_label_hide_links', array('sanitize_callback' => 'absint'));

    add_settings_section('seo_fury_general_section', '', null, 'seo_fury_general_settings');

    add_settings_section('seo_fury_security_section', '', null, 'seo_fury_ssl_settings');

    add_settings_section('seo_fury_white_label_section', __('White Label', 'seo-fury'), array($this, 'white_label_section_callback'), 'seo_fury_general_settings');

    add_settings_field(
        'seo_fury_plugin_language',
        __('Plugin Language', 'seo-fury'),
        array($this, 'plugin_language_callback'),
        'seo_fury_general_settings',
        'seo_fury_general_section'
    );

    add_settings_field(
        'seo_fury_transliterate_urls',
        __('URL Transliteration', 'seo-fury'),
        array($this, 'transliterate_urls_callback'),
        'seo_fury_general_settings',
        'seo_fury_general_section'
    );

    add_settings_field(
        'seo_fury_white_label_enabled',
        __('Enable White Label', 'seo-fury'),
        array($this, 'white_label_enabled_callback'),
        'seo_fury_general_settings',
        'seo_fury_white_label_section'
    );

    add_settings_field(
        'seo_fury_white_label_name',
        __('Plugin Name', 'seo-fury'),
        array($this, 'white_label_name_callback'),
        'seo_fury_general_settings',
        'seo_fury_white_label_section'
    );

        add_settings_field(
            'seo_fury_white_label_hide_links',
            __('Hide Branding Links', 'seo-fury'),
        array($this, 'white_label_hide_links_callback'),
        'seo_fury_general_settings',
        'seo_fury_white_label_section'
    );

    add_settings_field('seo_fury_bulk_transliterate', __('Bulk URL Conversion', 'seo-fury'), array($this, 'bulk_transliterate_callback'), 'seo_fury_general_settings', 'seo_fury_general_section');

    add_settings_field('seo_fury_force_https', __('Force HTTPS', 'seo-fury'), array($this, 'force_https_callback'), 'seo_fury_ssl_settings', 'seo_fury_security_section');
    add_settings_field('seo_fury_fix_mixed_content', __('Fix Mixed Content', 'seo-fury'), array($this, 'fix_mixed_content_callback'), 'seo_fury_ssl_settings', 'seo_fury_security_section');
    add_settings_field('seo_fury_enable_hsts', __('HSTS Header', 'seo-fury'), array($this, 'enable_hsts_callback'), 'seo_fury_ssl_settings', 'seo_fury_security_section');
    add_settings_field('seo_fury_www_redirect', __('WWW Redirect', 'seo-fury'), array($this, 'www_redirect_callback'), 'seo_fury_ssl_settings', 'seo_fury_security_section');
}

    public function general_section_callback() {
        echo '<p>' . esc_html__('Configure the main SEO settings for your site.', 'seo-fury') . '</p>';
    }

    public function plugin_language_callback() {
        $current = get_option('seo_fury_plugin_language', '');
        $languages = array(
            ''      => '🌐 ' . __('Auto (WordPress language)', 'seo-fury'),
            'en_US' => '🇬🇧 English',
            'ru_RU' => '🇷🇺 Русский',
            'de_DE' => '🇩🇪 Deutsch',
            'fr_FR' => '🇫🇷 Français',
            'es_ES' => '🇪🇸 Español',
        );
        ?>
        <select name="seo_fury_plugin_language" onchange="HTMLFormElement.prototype.submit.call(this.form);">
            <?php foreach ($languages as $code => $label) : ?>
                <option value="<?php echo esc_attr($code); ?>" <?php selected($current, $code); ?>>
                    <?php echo esc_html($label); ?>
                </option>
            <?php endforeach; ?>
        </select>
        <p class="description">
            <?php esc_html_e('Choose the language for the plugin admin interface. "Auto" follows your WordPress site language.', 'seo-fury'); ?>
        </p>
        <?php
    }

    public function transliterate_urls_callback() {
        $enabled = get_option('seo_fury_transliterate_urls', 0);
        ?>
        <label>
            <input type="checkbox" name="seo_fury_transliterate_urls" value="1" <?php checked($enabled, 1); ?>>
            <?php esc_html_e('Enable automatic transliteration for non-Latin URLs', 'seo-fury'); ?>
        </label>
        <p class="description">
            <?php esc_html_e('Automatically converts non-Latin characters to Latin in post and page URLs.', 'seo-fury'); ?>
        </p>
        <?php
    }

    public function sanitize_checkbox($input) {
        return ($input == 1) ? 1 : 0;
    }

public function transliterate_slug($slug, $raw_title = '', $context = 'save', $force = false) {
    if (!$force && !get_option('seo_fury_transliterate_urls', 0)) {
        return $slug;
    }

    $text = !empty($raw_title) ? $raw_title : urldecode($slug);

    if (!preg_match('/[А-Яа-яЁёІіЇїЄєҐґ]/u', $text)) {
        return $slug;
    }

    $transliteration = array(
        'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd',
        'е' => 'e', 'ё' => 'yo', 'ж' => 'zh', 'з' => 'z', 'и' => 'i',
        'й' => 'y', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n',
        'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't',
        'у' => 'u', 'ф' => 'f', 'х' => 'h', 'ц' => 'ts', 'ч' => 'ch',
        'ш' => 'sh', 'щ' => 'sch', 'ъ' => '', 'ы' => 'y', 'ь' => '',
        'э' => 'e', 'ю' => 'yu', 'я' => 'ya',
        'А' => 'A', 'Б' => 'B', 'В' => 'V', 'Г' => 'G', 'Д' => 'D',
        'Е' => 'E', 'Ё' => 'Yo', 'Ж' => 'Zh', 'З' => 'Z', 'И' => 'I',
        'Й' => 'Y', 'К' => 'K', 'Л' => 'L', 'М' => 'M', 'Н' => 'N',
        'О' => 'O', 'П' => 'P', 'Р' => 'R', 'С' => 'S', 'Т' => 'T',
        'У' => 'U', 'Ф' => 'F', 'Х' => 'H', 'Ц' => 'Ts', 'Ч' => 'Ch',
        'Ш' => 'Sh', 'Щ' => 'Sch', 'Ъ' => '', 'Ы' => 'Y', 'Ь' => '',
        'Э' => 'E', 'Ю' => 'Yu', 'Я' => 'Ya',
        'і' => 'i', 'ї' => 'yi', 'є' => 'ye', 'ґ' => 'g',
        'І' => 'I', 'Ї' => 'Yi', 'Є' => 'Ye', 'Ґ' => 'G',
    );

    $transliterated = strtr($text, $transliteration);

    $transliterated = mb_strtolower($transliterated, 'UTF-8');

    $transliterated = preg_replace('/[^a-z0-9]+/i', '-', $transliterated);

    $transliterated = trim($transliterated, '-');

    $transliterated = preg_replace('/-+/', '-', $transliterated);

    return $transliterated;
}

/**
 * Transliterate Cyrillic characters in uploaded file names.
 *
 * Hooked to `sanitize_file_name` at priority 5 (before WP core strips
 * non-ASCII characters at priority 10). Preserves file extension, converts
 * Cyrillic → Latin, replaces spaces/special chars with hyphens.
 *
 * Example: "Фотография природы.jpg" → "fotografiya-prirody.jpg"
 *
 * @param string $filename The sanitized filename.
 * @return string Transliterated filename.
 */
public function transliterate_filename($filename) {
    if (!get_option('seo_fury_transliterate_urls', 0)) {
        return $filename;
    }

    // Separate extension from the name
    $ext  = pathinfo($filename, PATHINFO_EXTENSION);
    $name = pathinfo($filename, PATHINFO_FILENAME);

    // Only process if there are Cyrillic characters
    if (!preg_match('/[А-Яа-яЁёІіЇїЄєҐґ]/u', $name)) {
        return $filename;
    }

    $transliteration = array(
        'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd',
        'е' => 'e', 'ё' => 'yo', 'ж' => 'zh', 'з' => 'z', 'и' => 'i',
        'й' => 'y', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n',
        'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't',
        'у' => 'u', 'ф' => 'f', 'х' => 'h', 'ц' => 'ts', 'ч' => 'ch',
        'ш' => 'sh', 'щ' => 'sch', 'ъ' => '', 'ы' => 'y', 'ь' => '',
        'э' => 'e', 'ю' => 'yu', 'я' => 'ya',
        'А' => 'A', 'Б' => 'B', 'В' => 'V', 'Г' => 'G', 'Д' => 'D',
        'Е' => 'E', 'Ё' => 'Yo', 'Ж' => 'Zh', 'З' => 'Z', 'И' => 'I',
        'Й' => 'Y', 'К' => 'K', 'Л' => 'L', 'М' => 'M', 'Н' => 'N',
        'О' => 'O', 'П' => 'P', 'Р' => 'R', 'С' => 'S', 'Т' => 'T',
        'У' => 'U', 'Ф' => 'F', 'Х' => 'H', 'Ц' => 'Ts', 'Ч' => 'Ch',
        'Ш' => 'Sh', 'Щ' => 'Sch', 'Ъ' => '', 'Ы' => 'Y', 'Ь' => '',
        'Э' => 'E', 'Ю' => 'Yu', 'Я' => 'Ya',
        'і' => 'i', 'ї' => 'yi', 'є' => 'ye', 'ґ' => 'g',
        'І' => 'I', 'Ї' => 'Yi', 'Є' => 'Ye', 'Ґ' => 'G',
    );

    $name = strtr($name, $transliteration);
    $name = mb_strtolower($name, 'UTF-8');
    $name = preg_replace('/[^a-z0-9]+/i', '-', $name);
    $name = trim($name, '-');
    $name = preg_replace('/-+/', '-', $name);

    if (empty($name)) {
        $name = 'image';
    }

    return $ext ? $name . '.' . $ext : $name;
}

/**
 * Transliterate slug when a post is inserted/updated (Gutenberg + REST API).
 *
 * Gutenberg generates slugs client-side via JS cleanForSlug() which strips
 * Cyrillic characters, producing empty/garbage slugs. This filter runs on
 * wp_insert_post_data (priority 10) and fixes the slug before the row is
 * written to the database.
 *
 * @param array $data    Slashed, sanitised post data.
 * @param array $postarr Raw post array (includes 'ID').
 * @return array
 */
public function transliterate_on_insert( $data, $postarr ) {
    if ( ! get_option( 'seo_fury_transliterate_urls', 0 ) ) {
        return $data;
    }

    $post_name  = isset( $data['post_name'] ) ? $data['post_name'] : '';
    $post_title = isset( $data['post_title'] ) ? $data['post_title'] : '';

    // Skip revisions.
    if ( isset( $data['post_type'] ) && 'revision' === $data['post_type'] ) {
        return $data;
    }

    // Decode the slug (Gutenberg may URL-encode it).
    $decoded_slug = urldecode( $post_name );

    // Case 1: Slug already contains Cyrillic — transliterate it directly.
    if ( preg_match( '/[А-Яа-яЁёІіЇїЄєҐґ]/u', $decoded_slug ) ) {
        $data['post_name'] = $this->transliterate_slug( $decoded_slug, $decoded_slug, 'save', true );
        return $data;
    }

    // Case 2: Title is Cyrillic but slug is empty / auto-generated / garbage.
    //
    // Gutenberg creates auto-draft with default title "Черновик"/"Auto Draft",
    // which may already be transliterated to "chernovik"/"auto-draft" by the
    // time the user changes the title. When the user types a real Cyrillic
    // title, Gutenberg does NOT regenerate the slug — it keeps "chernovik".
    // We detect these stale auto-generated slugs and regenerate from title.
    if ( ! empty( $post_title ) && preg_match( '/[А-Яа-яЁёІіЇїЄєҐґ]/u', $post_title ) ) {

        // Known auto-draft / placeholder slug patterns (Latin).
        $auto_draft_patterns = array(
            'chernovik', 'chernovik-2', 'chernovik-3',
            'auto-draft', 'auto-draft-2', 'auto-draft-3',
        );

        // Slugs that indicate "not manually set by the user".
        $is_auto_slug = empty( $post_name )
            || '' === trim( $post_name, '-' )
            || preg_match( '/^[0-9-]+$/', $post_name )                           // "2", "-2"
            || preg_match( '/^__trashed/', $post_name )                           // trashed posts
            || preg_match( '/^%[0-9a-f]{2}/i', $post_name )                      // URL-encoded Cyrillic
            || in_array( preg_replace( '/-\d+$/', '', $post_name ), $auto_draft_patterns, true ); // "chernovik-4" etc.

        // Also check: if slug doesn't look like it was derived from the current title,
        // it's probably stale. Generate transliterated version of title and compare.
        if ( ! $is_auto_slug ) {
            $expected_slug = $this->transliterate_slug( $post_title, $post_title, 'save', true );
            // If current slug has zero overlap with expected (e.g. "chernovik" vs "tury-v-tayand"),
            // it's stale. But only for new posts or drafts to avoid overwriting manual slugs.
            $post_status = isset( $data['post_status'] ) ? $data['post_status'] : '';
            if ( in_array( $post_status, array( 'auto-draft', 'draft' ), true ) ) {
                // Check if current slug starts with the first word of expected slug.
                $first_word = explode( '-', $expected_slug )[0];
                if ( ! empty( $first_word ) && strlen( $first_word ) > 2 && strpos( $post_name, $first_word ) === false ) {
                    $is_auto_slug = true;
                }
            }
        }

        if ( $is_auto_slug ) {
            $data['post_name'] = $this->transliterate_slug( $post_title, $post_title, 'save', true );
        }
    }

    return $data;
}

/**
 * Transliterate slug at the wp_unique_post_slug stage.
 *
 * This is the final safety net — runs after WP has generated a unique slug
 * but before it's saved. Catches edge cases missed by sanitize_title and
 * wp_insert_post_data (e.g. Quick Edit, Bulk Edit, XML-RPC).
 *
 * @param string $slug          The post slug.
 * @param int    $post_id       Post ID.
 * @param string $post_status   Post status.
 * @param string $post_type     Post type.
 * @param int    $post_parent   Post parent ID.
 * @param string $original_slug The original slug before uniqueness suffix.
 * @return string
 */
public function transliterate_unique_slug( $slug, $post_id, $post_status, $post_type, $post_parent, $original_slug ) {
    if ( ! get_option( 'seo_fury_transliterate_urls', 0 ) ) {
        return $slug;
    }

    // Skip revisions & nav menu items.
    if ( in_array( $post_type, array( 'revision', 'nav_menu_item' ), true ) ) {
        return $slug;
    }

    $decoded = urldecode( $slug );

    if ( preg_match( '/[А-Яа-яЁёІіЇїЄєҐґ]/u', $decoded ) ) {
        $transliterated = $this->transliterate_slug( $decoded, $decoded, 'save', true );

        // If WP added a uniqueness suffix (-2, -3), preserve it.
        if ( $slug !== $original_slug && preg_match( '/-(\d+)$/', $slug, $m ) ) {
            $transliterated .= '-' . $m[1];
        }

        return $transliterated;
    }

    return $slug;
}

/**
 * Fix slug AFTER a post has been saved to the database.
 *
 * This is the absolute last resort. It runs after wp_insert_post() and
 * directly updates the slug in the DB if it's still non-Latin while the
 * title is Cyrillic. Covers:
 *   - auto-draft → draft (Gutenberg first save)
 *   - draft → publish (publication)
 *   - Quick Edit / Bulk Edit
 *   - WooCommerce product creation
 *
 * @param int      $post_id Post ID.
 * @param \WP_Post $post    Post object.
 * @param bool     $update  Whether this is an update.
 */
public function fix_slug_after_save( $post_id, $post, $update ) {
    if ( ! get_option( 'seo_fury_transliterate_urls', 0 ) ) {
        return;
    }

    // Skip revisions, auto-saves, nav menu items.
    if ( wp_is_post_revision( $post_id ) || wp_is_post_autosave( $post_id ) ) {
        return;
    }
    if ( in_array( $post->post_type, array( 'revision', 'nav_menu_item' ), true ) ) {
        return;
    }

    $title = $post->post_title;
    $slug  = $post->post_name;

    // Only act if the title contains Cyrillic.
    if ( empty( $title ) || ! preg_match( '/[А-Яа-яЁёІіЇїЄєҐґ]/u', $title ) ) {
        return;
    }

    $decoded_slug = urldecode( $slug );

    // Generate the expected transliterated slug from the title.
    $expected_slug = $this->transliterate_slug( $title, $title, 'save', true );

    // If slug already matches what we'd generate — nothing to do.
    if ( $slug === $expected_slug || strpos( $slug, $expected_slug ) === 0 ) {
        return;
    }

    // Check if slug needs fixing: still Cyrillic, auto-generated, or stale.
    $auto_draft_bases = array( 'chernovik', 'auto-draft' );
    $slug_base        = preg_replace( '/-\d+$/', '', $slug ); // strip "-2", "-3" suffixes

    $needs_fix = empty( $slug )
        || preg_match( '/[А-Яа-яЁёІіЇїЄєҐґ]/u', $decoded_slug )
        || preg_match( '/^%[0-9a-f]{2}/i', $slug )
        || preg_match( '/^[0-9]+(-[0-9]+)?$/', $slug )
        || in_array( $slug_base, $auto_draft_bases, true );

    // For drafts: also check if slug doesn't match the title at all.
    if ( ! $needs_fix && in_array( $post->post_status, array( 'auto-draft', 'draft' ), true ) ) {
        $first_word = explode( '-', $expected_slug )[0];
        if ( ! empty( $first_word ) && strlen( $first_word ) > 2 && strpos( $slug, $first_word ) === false ) {
            $needs_fix = true;
        }
    }

    if ( ! $needs_fix ) {
        return;
    }

    // Prevent infinite loop: remove this action while updating.
    remove_action( 'wp_insert_post', array( $this, 'fix_slug_after_save' ), 10 );

    $new_slug = $expected_slug; // Already computed above.

    if ( ! empty( $new_slug ) && $new_slug !== $slug ) {
        // Ensure uniqueness.
        $new_slug = wp_unique_post_slug( $new_slug, $post_id, $post->post_status, $post->post_type, $post->post_parent );

        wp_update_post( array(
            'ID'        => $post_id,
            'post_name' => $new_slug,
        ) );
    }

    // Re-add the action.
    add_action( 'wp_insert_post', array( $this, 'fix_slug_after_save' ), 10, 3 );
}

public function ajax_bulk_transliterate() {
    check_ajax_referer('seo_bulk_transliterate_nonce', 'nonce');

    if (!current_user_can('manage_options')) {
        wp_send_json_error(__('Insufficient permissions.', 'seo-fury'));
    }

    $post_types = isset($_POST['post_types']) ? array_map('sanitize_text_field', $_POST['post_types']) : array('post', 'page');

    $args = array(
        'post_type' => $post_types,
        'post_status' => 'any',
        'posts_per_page' => -1,
        'fields' => 'ids'
    );

    $posts = get_posts($args);
    $updated = 0;
    $skipped = 0;

    foreach ($posts as $post_id) {
        $post = get_post($post_id);
        $current_slug = $post->post_name;

        $decoded_slug = urldecode($current_slug);

        $has_cyrillic = preg_match('/[А-Яа-яЁёІіЇїЄєҐґ]/u', $decoded_slug);

        $has_url_encoded = preg_match('/%[0-9A-F]{2}/', $current_slug);

        if ($has_cyrillic || $has_url_encoded) {
            $new_slug = $this->transliterate_slug($decoded_slug, $post->post_title, 'save', true);

            if (!empty($new_slug) && !preg_match('/[А-Яа-яЁёІіЇїЄєҐґ%]/u', $new_slug)) {
                $result = wp_update_post(array(
                    'ID' => $post_id,
                    'post_name' => $new_slug
                ), true);

                if (!is_wp_error($result)) {
                    $updated++;
                } else {
                    $skipped++;
                }
            } else {
                $skipped++;
            }
        } else {
            $skipped++;
        }
    }

    wp_send_json_success(array(
        'updated' => $updated,
        'skipped' => $skipped,
        'total' => count($posts)
    ));
}

public function ajax_get_url_stats() {
    check_ajax_referer('seo_bulk_transliterate_nonce', 'nonce');

    if (!current_user_can('manage_options')) {
        wp_send_json_error(__('Insufficient permissions.', 'seo-fury'));
    }

    $post_types = isset($_POST['post_types']) ? array_map('sanitize_text_field', $_POST['post_types']) : array('post', 'page');

    $args = array(
        'post_type' => $post_types,
        'post_status' => 'any',
        'posts_per_page' => -1,
        'fields' => 'ids'
    );

    $posts = get_posts($args);
    $cyrillic_count = 0;
    $latin_count = 0;
    $cyrillic_items = array();

    foreach ($posts as $post_id) {
        $post = get_post($post_id);
        $slug = $post->post_name;

        $decoded_slug = urldecode($slug);

        if (preg_match('/[А-Яа-яЁёІіЇїЄєҐґ]/u', $decoded_slug) || preg_match('/%[0-9A-F]{2}/', $slug)) {
            $cyrillic_count++;
            $permalink = get_permalink($post_id);
            $cyrillic_items[] = array(
                'id'        => $post_id,
                'title'     => $post->post_title !== '' ? $post->post_title : __('(no title)', 'seo-fury'),
                'slug'      => $decoded_slug,
                'url'       => $permalink,
                'url_label' => urldecode($permalink),
                'edit_url'  => get_edit_post_link($post_id, 'raw'),
                'post_type' => $post->post_type,
                'status'    => $post->post_status,
            );
        } else {
            $latin_count++;
        }
    }

    wp_send_json_success(array(
        'total'           => count($posts),
        'cyrillic'        => $cyrillic_count,
        'latin'           => $latin_count,
        'cyrillic_items'  => $cyrillic_items,
    ));
}

public function bulk_transliterate_callback() {
    ?>
    <div class="seo-card" style="max-width: 800px;">
        <p><?php esc_html_e('Convert existing non-Latin URLs to Latin slugs.', 'seo-fury'); ?></p>

        <div id="url-stats" style="background: var(--sf-gray-50,#f6f7f7); border: 1px solid var(--sf-gray-200,#e5e7eb); color: var(--sf-gray-700); padding: 15px; border-radius: 8px; margin-bottom: 15px;">
            <p style="margin: 0;"><strong><?php esc_html_e('Loading stats...', 'seo-fury'); ?></strong></p>
        </div>

        <p>
            <?php
            $post_types = get_post_types( array( 'public' => true ), 'objects' );
            foreach ( $post_types as $pt ) :
                if ( $pt->name === 'attachment' ) continue;
            ?>
            <label style="display: block; margin-bottom: 10px;">
                <input type="checkbox" name="bulk_post_types[]" value="<?php echo esc_attr( $pt->name ); ?>" checked>
                <?php echo esc_html( $pt->labels->name ); ?>
            </label>
            <?php endforeach; ?>
        </p>

        <p>
            <button type="button" id="refresh-url-stats" class="button"><?php echo '🔄 ' . esc_html__('Refresh Stats', 'seo-fury'); ?></button>
            <button type="button" id="bulk-transliterate-btn" class="button button-primary"><?php echo '🚀 ' . esc_html__('Convert URLs', 'seo-fury'); ?></button>
        </p>

        <div id="bulk-transliterate-result" style="margin-top: 15px;"></div>
    </div>

    <script>
    jQuery(document).ready(function($) {
        function escapeHtml(str) {
            if (str === null || typeof str === 'undefined') return '';
            return String(str)
                .replace(/&/g, '&amp;')
                .replace(/</g, '&lt;')
                .replace(/>/g, '&gt;')
                .replace(/"/g, '&quot;')
                .replace(/'/g, '&#39;');
        }
        function escapeAttr(str) {
            return escapeHtml(str);
        }

        loadUrlStats();

        $('#refresh-url-stats').on('click', function() {
            loadUrlStats();
        });

        function loadUrlStats() {
            var postTypes = [];
            $('input[name="bulk_post_types[]"]:checked').each(function() {
                postTypes.push($(this).val());
            });

            $.ajax({
                url: ajaxurl,
                type: 'POST',
                data: {
                    action: 'seo_get_url_stats',
                    nonce: '<?php echo esc_js( wp_create_nonce('seo_bulk_transliterate_nonce') ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>',
                    post_types: postTypes
                },
                success: function(response) {
                    if (response.success) {
                        var html = '<p style="margin: 0;"><strong><?php echo esc_js(__('URL stats:', 'seo-fury')); ?></strong></p>';
                        html += '<p style="margin: 5px 0;"><?php echo esc_js(__('Total:', 'seo-fury')); ?> <strong>' + response.data.total + '</strong></p>';
                        html += '<p style="margin: 5px 0;"><?php echo esc_js(__('Non-Latin:', 'seo-fury')); ?> <strong style="color: #d63638;">' + response.data.cyrillic + '</strong></p>';
                        html += '<p style="margin: 5px 0;"><?php echo esc_js(__('Latin:', 'seo-fury')); ?> <strong style="color: #00a32a;">' + response.data.latin + '</strong></p>';

                        var items = response.data.cyrillic_items || [];
                        if (items.length) {
                            html += '<details style="margin-top: 10px;" open>';
                            html += '<summary style="cursor: pointer; font-weight: 600; color: #d63638;"><?php echo esc_js(__('Non-Latin URLs', 'seo-fury')); ?> (' + items.length + ')</summary>';
                            html += '<div style="margin-top: 8px; max-height: 320px; overflow-y: auto; background: var(--sf-white,#fff); border: 1px solid var(--sf-gray-200,#dcdcde); border-radius: 4px;">';
                            html += '<table class="widefat striped" style="margin: 0; border: 0;"><thead><tr>';
                            html += '<th style="width: 35%;"><?php echo esc_js(__('Title', 'seo-fury')); ?></th>';
                            html += '<th><?php echo esc_js(__('URL', 'seo-fury')); ?></th>';
                            html += '<th style="width: 140px;"><?php echo esc_js(__('Actions', 'seo-fury')); ?></th>';
                            html += '</tr></thead><tbody>';
                            for (var i = 0; i < items.length; i++) {
                                var it = items[i];
                                html += '<tr>';
                                html += '<td><strong>' + escapeHtml(it.title) + '</strong>'
                                     +  '<br><span style="color: var(--sf-gray-500,#646970); font-size: 12px;">' + escapeHtml(it.post_type) + ' · ' + escapeHtml(it.status) + '</span></td>';
                                html += '<td><code style="word-break: break-all; background: var(--sf-gray-100, #f6f7f7); padding: 2px 5px; border-radius: 3px; font-size: 12px;">' + escapeHtml(it.url_label) + '</code></td>';
                                html += '<td>';
                                if (it.url)      html += '<a href="' + escapeAttr(it.url) + '" target="_blank" rel="noopener" class="button button-small" style="margin-right: 4px;">👁 <?php echo esc_js(__('Open', 'seo-fury')); ?></a>';
                                if (it.edit_url) html += '<a href="' + escapeAttr(it.edit_url) + '" target="_blank" rel="noopener" class="button button-small">✏️ <?php echo esc_js(__('Edit', 'seo-fury')); ?></a>';
                                html += '</td>';
                                html += '</tr>';
                            }
                            html += '</tbody></table></div></details>';
                        }

                        $('#url-stats').html(html);
                    }
                }
            });
        }

        $('#bulk-transliterate-btn').on('click', function() {
            if (!confirm('<?php echo esc_js(__('Are you sure? This will change URLs for all posts with non-Latin slugs.', 'seo-fury')); ?>\n\n<?php echo esc_js(__('We recommend backing up the database first.', 'seo-fury')); ?>')) {
                return;
            }

            var postTypes = [];
            $('input[name="bulk_post_types[]"]:checked').each(function() {
                postTypes.push($(this).val());
            });

            var btn = $(this);
            var originalText = btn.text();
            btn.prop('disabled', true).text('⏳ <?php echo esc_js(__('Converting...', 'seo-fury')); ?>');

            $.ajax({
                url: ajaxurl,
                type: 'POST',
                data: {
                    action: 'seo_bulk_transliterate',
                    nonce: '<?php echo esc_js( wp_create_nonce('seo_bulk_transliterate_nonce') ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>',
                    post_types: postTypes
                },
                success: function(response) {
                    if (response.success) {
                        var html = '<div class="seo-alert success">';
                        html += '<strong>✅ <?php echo esc_js(__('Conversion completed!', 'seo-fury')); ?></strong><br>';
                        html += '<?php echo esc_js(__('Updated:', 'seo-fury')); ?> <strong>' + response.data.updated + '</strong><br>';
                        html += '<?php echo esc_js(__('Skipped (already Latin):', 'seo-fury')); ?> <strong>' + response.data.skipped + '</strong><br>';
                        html += '<?php echo esc_js(__('Total checked:', 'seo-fury')); ?> <strong>' + response.data.total + '</strong>';
                        html += '</div>';
                        $('#bulk-transliterate-result').html(html);
                        loadUrlStats();
                    } else {
                        $('#bulk-transliterate-result').html('<div class="seo-alert error"><strong>❌ <?php echo esc_js(__('Error:', 'seo-fury')); ?></strong> ' + response.data + '</div>');
                    }
                },
                error: function() {
                    $('#bulk-transliterate-result').html('<div class="seo-alert error"><strong>❌ <?php echo esc_js(__('Server connection error', 'seo-fury')); ?></strong></div>');
                },
                complete: function() {
                    btn.prop('disabled', false).text(originalText);
                }
            });
        });
    });
    </script>
    <?php
}

    public function security_section_callback() {
        echo '<p>' . esc_html__('Configure HTTPS enforcement, HSTS headers, and WWW redirect.', 'seo-fury') . '</p>';
    }

    public function force_https_callback() {
        $enabled = get_option('seo_fury_force_https', 0);
        $has_ssl = is_ssl();
        ?>
        <label>
            <input type="checkbox" name="seo_fury_force_https" value="1" <?php checked($enabled, 1); ?>>
            <?php esc_html_e('Redirect all HTTP requests to HTTPS (301)', 'seo-fury'); ?>
        </label>
        <p class="description"><?php esc_html_e('Requires a valid SSL certificate installed on your server.', 'seo-fury'); ?></p>
        <?php if (!$has_ssl && !$enabled): ?>
            <p class="description" style="color: #D97706; margin-top: 6px;">
                ⚠️ <?php esc_html_e('Warning: Your current connection is not HTTPS. Make sure you have a valid SSL certificate installed before enabling this option, otherwise you may lose access to your site.', 'seo-fury'); ?>
            </p>
        <?php endif; ?>
        <?php if ($enabled): ?>
            <p class="description" style="color: var(--sf-gray-500, #64748b); margin-top: 6px;">
                ℹ️ <?php esc_html_e('The browser header "Content-Security-Policy: upgrade-insecure-requests" will also be sent automatically to upgrade all sub-resources to HTTPS.', 'seo-fury'); ?>
            </p>
            <p class="description" style="color: var(--sf-gray-400, #94a3b8); margin-top: 4px;">
                🛟 <?php esc_html_e('Emergency bypass: add ?seo_fury_no_ssl=1 to your URL if you get locked out after enabling this.', 'seo-fury'); ?>
            </p>
        <?php endif; ?>
        <?php
    }

    public function fix_mixed_content_callback() {
        $enabled = get_option('seo_fury_fix_mixed_content', 0);
        ?>
        <label>
            <input type="checkbox" name="seo_fury_fix_mixed_content" value="1" <?php checked($enabled, 1); ?>>
            <?php esc_html_e('Automatically replace HTTP with HTTPS in page output', 'seo-fury'); ?>
        </label>
        <p class="description"><?php esc_html_e('Fixes mixed content warnings by rewriting internal HTTP URLs to HTTPS on the frontend.', 'seo-fury'); ?></p>
        <?php
    }

    public function enable_hsts_callback() {
        $enabled = get_option('seo_fury_enable_hsts', 0);
        $max_age = get_option('seo_fury_hsts_max_age', 31536000);
        ?>
        <label>
            <input type="checkbox" name="seo_fury_enable_hsts" value="1" <?php checked($enabled, 1); ?>>
            <?php esc_html_e('Send Strict-Transport-Security header', 'seo-fury'); ?>
        </label>
        <div style="margin-top: 8px;">
            <label><?php esc_html_e('Max-Age (seconds):', 'seo-fury'); ?>
                <input type="number" name="seo_fury_hsts_max_age" value="<?php echo esc_attr($max_age); ?>" min="0" style="width: 120px;">
            </label>
            <span class="description" style="margin-left: 8px;"><?php esc_html_e('Default: 31536000 (1 year)', 'seo-fury'); ?></span>
        </div>
        <p class="description"><?php esc_html_e('Tells browsers to always use HTTPS for this domain. Only enable if SSL is fully configured.', 'seo-fury'); ?></p>
        <?php
    }

    public function www_redirect_callback() {
        $value = get_option('seo_fury_www_redirect', '');
        ?>
        <select name="seo_fury_www_redirect">
            <option value="" <?php selected($value, ''); ?>><?php esc_html_e('No redirect', 'seo-fury'); ?></option>
            <option value="force_www" <?php selected($value, 'force_www'); ?>><?php esc_html_e('Force www (redirect non-www to www)', 'seo-fury'); ?></option>
            <option value="force_no_www" <?php selected($value, 'force_no_www'); ?>><?php esc_html_e('Force non-www (redirect www to non-www)', 'seo-fury'); ?></option>
        </select>
        <p class="description"><?php esc_html_e('Enforce a canonical www or non-www version of your domain (301 redirect).', 'seo-fury'); ?></p>
        <?php
    }

    public function handle_security_redirects() {
        if (is_admin() || wp_doing_ajax() || (defined('REST_REQUEST') && REST_REQUEST) || (defined('WP_CLI') && WP_CLI)) {
            return;
        }

        // Validate HTTP_HOST against the expected site host to prevent open redirects
        $expected_host = wp_parse_url(home_url(), PHP_URL_HOST);
        $current_host = isset($_SERVER['HTTP_HOST']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_HOST'])) : '';
        $request_uri = isset($_SERVER['REQUEST_URI']) ? esc_url_raw(wp_unslash($_SERVER['REQUEST_URI'])) : '/';

        // Strip www. for comparison
        $current_host_bare = preg_replace('/^www\./', '', $current_host);
        $expected_host_bare = preg_replace('/^www\./', '', $expected_host);

        if ($current_host_bare !== $expected_host_bare) {
            return; // Host mismatch — do not redirect to prevent open redirect
        }

        $force_https = get_option('seo_fury_force_https', 0);
        if ($force_https && !is_ssl()) {
            // Safety: allow bypass with ?seo_fury_no_ssl=1 to prevent lockout
            if (isset($_GET['seo_fury_no_ssl']) && $_GET['seo_fury_no_ssl'] === '1') {
                return;
            }

            $redirect_url = 'https://' . $current_host . $request_uri;
            wp_redirect($redirect_url, 301);
            exit;
        }

        $www_redirect = get_option('seo_fury_www_redirect', '');
        if (!empty($www_redirect)) {
            $scheme = is_ssl() ? 'https' : 'http';

            if ($www_redirect === 'force_www' && strpos($current_host, 'www.') !== 0) {
                wp_redirect($scheme . '://www.' . $current_host . $request_uri, 301);
                exit;
            } elseif ($www_redirect === 'force_no_www' && strpos($current_host, 'www.') === 0) {
                $host_no_www = substr($current_host, 4);
                wp_redirect($scheme . '://' . $host_no_www . $request_uri, 301);
                exit;
            }
        }
    }

    public function send_security_headers() {
        // HSTS header — only when already on HTTPS
        if (get_option('seo_fury_enable_hsts', 0) && is_ssl()) {
            $max_age = intval(get_option('seo_fury_hsts_max_age', 31536000));
            header('Strict-Transport-Security: max-age=' . $max_age . '; includeSubDomains');
        }

        // Upgrade insecure requests — tells browsers to automatically upgrade HTTP sub-resources to HTTPS
        if (get_option('seo_fury_force_https', 0) && is_ssl()) {
            header('Content-Security-Policy: upgrade-insecure-requests');
        }
    }

    public function start_mixed_content_buffer() {
        if (is_admin()) {
            return;
        }
        ob_start(array($this, 'fix_mixed_content_output'));
    }

    public function fix_mixed_content_output($buffer) {
        $site_url = site_url();
        $parsed = wp_parse_url($site_url);
        $domain = isset($parsed['host']) ? $parsed['host'] : '';
        if (empty($domain)) {
            return $buffer;
        }

        // Strip www. for bare domain
        $bare_domain = preg_replace('/^www\./', '', $domain);

        // Replace http:// with https:// for main domain and www variant
        $buffer = str_replace('http://' . $bare_domain, 'https://' . $bare_domain, $buffer);
        $buffer = str_replace('http://www.' . $bare_domain, 'https://www.' . $bare_domain, $buffer);

        // Also fix protocol-relative URLs that may have been incorrectly set as http
        // Fix src="http:// and href="http:// for the same domain in HTML attributes
        $buffer = preg_replace(
            '/(src|href|action|data-src|data-href|poster|srcset)=(["\'])http:\/\/(www\.)?' . preg_quote($bare_domain, '/') . '/i',
            '$1=$2https://$3' . $bare_domain,
            $buffer
        );

        // Fix url() references in inline styles
        $buffer = preg_replace(
            '/url\(\s*(["\']?)http:\/\/(www\.)?' . preg_quote($bare_domain, '/') . '/i',
            'url($1https://$2' . $bare_domain,
            $buffer
        );

        return $buffer;
    }

    public function white_label_section_callback() {
        $core = SEO_Fury_Core::get_instance();
        $pro = $core->get_pro_features();
        $is_pro = $pro->is_pro();
        ob_start();

        $white_label_enabled = get_option('seo_fury_white_label_enabled', 0);
        $hide_links = get_option('seo_fury_white_label_hide_links', 0);
        $should_hide = $white_label_enabled && $hide_links;

        if (!$is_pro && !$should_hide) {
            ?>
            <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; border-radius: 8px; margin: 20px 0;">
                <div style="display: flex; align-items: center; gap: 20px;">
                    <div style="font-size: 48px;">🎭</div>
                    <div>
                        <h3 style="color: white; margin: 0 0 8px 0;"><?php esc_html_e('White Label is a PRO feature', 'seo-fury'); ?></h3>
                        <p style="margin: 0 0 12px 0; opacity: 0.95;">
                            <?php esc_html_e('Rename the plugin and remove branding. Perfect for agencies and resellers.', 'seo-fury'); ?>
                        </p>
                        <a href="https://seo-fury.com/#pricing" target="_blank" class="button button-primary" style="background: white; color: #667eea; border: none; font-weight: 600;">
                            <?php echo '🚀 ' . esc_html__('Upgrade to PRO', 'seo-fury'); ?>
                        </a>
                    </div>
                </div>
            </div>
            <?php
        } else {
            echo '<p>' . esc_html__('Customize the plugin branding for your product.', 'seo-fury') . '</p>';
        }
        echo wp_kses_post( ob_get_clean() ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
    }

    public function white_label_enabled_callback() {
        $enabled = get_option('seo_fury_white_label_enabled', 0);
        $core = SEO_Fury_Core::get_instance();
        $pro = $core->get_pro_features();
        $is_pro = $pro->is_pro();
        $disabled = !$is_pro ? 'disabled' : '';
        $style = !$is_pro ? 'style="opacity: 0.5;"' : '';
        ?>
        <label <?php echo esc_attr($style); ?>>
            <input type="checkbox" name="seo_fury_white_label_enabled" value="1" <?php checked($enabled, 1); ?> <?php echo esc_attr($disabled); ?>>
            <?php esc_html_e('Enable white label', 'seo-fury'); ?>
        </label>
        <p class="description"><?php esc_html_e('When enabled, the plugin name changes across the admin UI.', 'seo-fury'); ?></p>
        <?php
    }

    public function white_label_name_callback() {
        $brand = function_exists('seo_fury_get_brand_name') ? seo_fury_get_brand_name() : 'SEO Fury';
        $name = get_option('seo_fury_white_label_name', $brand);
        $core = SEO_Fury_Core::get_instance();
        $pro = $core->get_pro_features();
        $is_pro = $pro->is_pro();
        $disabled = !$is_pro ? 'disabled' : '';
        $style = !$is_pro ? 'style="opacity: 0.5;"' : '';
        ?>
        <div <?php echo esc_attr($style); ?>>
            <input type="text"
                   name="seo_fury_white_label_name"
                   value="<?php echo esc_attr($name); ?>"
                   class="regular-text"
                   placeholder="<?php echo esc_attr($brand); ?>"
                   <?php echo esc_attr($disabled); ?>>
            <p class="description"><?php esc_html_e('New plugin name used across the UI.', 'seo-fury'); ?></p>
        </div>
        <?php
    }

    public function white_label_hide_links_callback() {
        $hide = get_option('seo_fury_white_label_hide_links', 0);

        $core = SEO_Fury_Core::get_instance();
        $pro = $core->get_pro_features();
        $is_pro = $pro->is_pro();
        $disabled = !$is_pro ? 'disabled' : '';
        $style = !$is_pro ? 'style="opacity: 0.5;"' : '';

        ?>
        <label <?php echo esc_attr($style); ?>>
            <input type="checkbox" name="seo_fury_white_label_hide_links" value="1" <?php checked($hide, 1); ?> <?php echo esc_attr($disabled); ?>>
            <?php esc_html_e('Hide all branding links', 'seo-fury'); ?>
        </label>
        <p class="description"><?php esc_html_e('Removes upgrade links and branding references.', 'seo-fury'); ?></p>
        <?php
    }

}
