<?php
/**
 * Meta tags — title, description, Open Graph, Twitter Cards, canonical, robots.
 *
 * Per-post overrides live in wp_seoforge_meta. Defaults inferred from the post.
 *
 * @package Brainwerk SEO Suite
 */

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

class Seoforge_Meta {

    public static function register( Seoforge_Loader $loader ) {
        if ( ! Seoforge_Settings::get( 'seo_meta_enabled', true ) ) {
            return;
        }
        if ( Seoforge_Compat::should_stand_down() ) {
            return;
        }
        $loader->add_filter( 'pre_get_document_title', __CLASS__, 'filter_title', 5 );
        $loader->add_filter( 'document_title_parts', __CLASS__, 'filter_title_parts' );
        $loader->add_action( 'wp_head', __CLASS__, 'render_meta', 1 );

        if ( Seoforge_Settings::get( 'seo_clean_head', true ) ) {
            remove_action( 'wp_head', 'wp_generator' );
            remove_action( 'wp_head', 'wlwmanifest_link' );
            remove_action( 'wp_head', 'rsd_link' );
        }
        if ( Seoforge_Settings::get( 'seo_remove_wp_emoji', true ) ) {
            remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
            remove_action( 'wp_print_styles', 'print_emoji_styles' );
        }
    }

    /** Returns the per-post meta row as array, or empty array. */
    public static function get_post_meta( $post_id ) {
        global $wpdb;
        $row = $wpdb->get_row( $wpdb->prepare(
            "SELECT * FROM %i WHERE blog_id = %d AND post_id = %d LIMIT 1",
            Seoforge_Utils::table( 'meta' ),
            Seoforge_Utils::current_blog_id(),
            (int) $post_id
        ), ARRAY_A );
        return is_array( $row ) ? $row : array();
    }

    public static function save_post_meta( $post_id, array $data ) {
        global $wpdb;
        $table = Seoforge_Utils::table( 'meta' );
        $existing = self::get_post_meta( $post_id );

        $clean = array(
            'blog_id'          => Seoforge_Utils::current_blog_id(),
            'post_id'          => (int) $post_id,
            'seo_title'        => isset( $data['seo_title'] ) ? mb_substr( sanitize_text_field( $data['seo_title'] ), 0, 255 ) : null,
            'seo_description'  => isset( $data['seo_description'] ) ? mb_substr( sanitize_textarea_field( $data['seo_description'] ), 0, 500 ) : null,
            'focus_keyword'    => isset( $data['focus_keyword'] ) ? mb_substr( sanitize_text_field( $data['focus_keyword'] ), 0, 120 ) : null,
            'og_title'         => isset( $data['og_title'] ) ? mb_substr( sanitize_text_field( $data['og_title'] ), 0, 255 ) : null,
            'og_description'   => isset( $data['og_description'] ) ? mb_substr( sanitize_textarea_field( $data['og_description'] ), 0, 500 ) : null,
            'og_image'         => isset( $data['og_image'] ) ? esc_url_raw( $data['og_image'] ) : null,
            'twitter_card'     => isset( $data['twitter_card'] ) ? sanitize_text_field( $data['twitter_card'] ) : null,
            'canonical'        => isset( $data['canonical'] ) ? esc_url_raw( $data['canonical'] ) : null,
            'robots_noindex'   => ! empty( $data['robots_noindex'] ) ? 1 : 0,
            'robots_nofollow'  => ! empty( $data['robots_nofollow'] ) ? 1 : 0,
            'score'            => isset( $data['score'] ) ? min( 100, max( 0, (int) $data['score'] ) ) : 0,
            'score_payload'    => isset( $data['score_payload'] ) ? wp_json_encode( $data['score_payload'] ) : null,
            'updated_at'       => current_time( 'mysql', 1 ),
        );
        if ( $existing ) {
            $wpdb->update( $table, $clean, array( 'id' => (int) $existing['id'] ) );
            return (int) $existing['id'];
        }
        $wpdb->insert( $table, $clean );
        return (int) $wpdb->insert_id;
    }

    public static function filter_title( $title ) {
        if ( ! is_singular() ) {
            return $title;
        }
        $post_id = get_queried_object_id();
        $meta = self::get_post_meta( $post_id );
        if ( ! empty( $meta['seo_title'] ) ) {
            return $meta['seo_title'];
        }
        return $title;
    }

    public static function filter_title_parts( $parts ) {
        if ( is_singular() ) {
            $meta = self::get_post_meta( get_queried_object_id() );
            if ( ! empty( $meta['seo_title'] ) ) {
                $parts['title'] = $meta['seo_title'];
            }
        }
        return $parts;
    }

    public static function render_meta() {
        if ( is_admin() ) {
            return;
        }
        $description = '';
        $og_title    = '';
        $og_image    = '';
        $canonical   = '';
        $noindex     = false;
        $nofollow    = false;

        if ( is_singular() ) {
            $post_id = get_queried_object_id();
            $meta    = self::get_post_meta( $post_id );
            $post    = get_post( $post_id );

            $description = ! empty( $meta['seo_description'] )
                ? $meta['seo_description']
                : self::auto_excerpt( $post );

            $og_title = ! empty( $meta['og_title'] ) ? $meta['og_title'] : get_the_title( $post_id );
            $og_image = ! empty( $meta['og_image'] ) ? $meta['og_image'] : (string) get_the_post_thumbnail_url( $post_id, 'large' );
            $canonical = ! empty( $meta['canonical'] ) ? $meta['canonical'] : get_permalink( $post_id );

            $noindex  = ! empty( $meta['robots_noindex'] );
            $nofollow = ! empty( $meta['robots_nofollow'] );
        } elseif ( is_home() || is_front_page() ) {
            $description = get_bloginfo( 'description' );
            $og_title    = get_bloginfo( 'name' );
            $canonical   = home_url( '/' );
        } elseif ( is_category() || is_tag() || is_tax() ) {
            $term = get_queried_object();
            if ( $term && ! empty( $term->description ) ) {
                $description = wp_strip_all_tags( $term->description );
            }
            $og_title  = single_term_title( '', false );
            $canonical = get_term_link( $term );
        }

        echo "\n<!-- Brainwerk SEO Suite -->\n";
        if ( $description ) {
            printf( "<meta name=\"description\" content=\"%s\">\n", esc_attr( wp_html_excerpt( $description, 160, '' ) ) );
        }
        if ( $noindex || $nofollow ) {
            $robots = array();
            $robots[] = $noindex  ? 'noindex'  : 'index';
            $robots[] = $nofollow ? 'nofollow' : 'follow';
            printf( "<meta name=\"robots\" content=\"%s\">\n", esc_attr( implode( ',', $robots ) ) );
        }
        if ( Seoforge_Settings::get( 'seo_canonical_enabled', true ) && $canonical ) {
            printf( "<link rel=\"canonical\" href=\"%s\">\n", esc_url( $canonical ) );
        }

        if ( Seoforge_Settings::get( 'seo_og_enabled', true ) ) {
            printf( "<meta property=\"og:type\" content=\"%s\">\n", is_singular() ? 'article' : 'website' );
            printf( "<meta property=\"og:site_name\" content=\"%s\">\n", esc_attr( get_bloginfo( 'name' ) ) );
            printf( "<meta property=\"og:locale\" content=\"%s\">\n", esc_attr( get_locale() ) );
            if ( $og_title ) {
                printf( "<meta property=\"og:title\" content=\"%s\">\n", esc_attr( $og_title ) );
            }
            if ( $description ) {
                printf( "<meta property=\"og:description\" content=\"%s\">\n", esc_attr( wp_html_excerpt( $description, 200, '' ) ) );
            }
            if ( $canonical ) {
                printf( "<meta property=\"og:url\" content=\"%s\">\n", esc_url( $canonical ) );
            }
            if ( $og_image ) {
                printf( "<meta property=\"og:image\" content=\"%s\">\n", esc_url( $og_image ) );
            }
        }

        if ( Seoforge_Settings::get( 'seo_twitter_enabled', true ) ) {
            $card = Seoforge_Settings::get( 'seo_default_twitter_card', 'summary_large_image' );
            printf( "<meta name=\"twitter:card\" content=\"%s\">\n", esc_attr( $card ) );
            // Deliberate product decision: one title/description field pair
            // feeds both OG and Twitter output, no separate twitter_title/
            // twitter_description fields. See docs/1.5-open-decisions.md #7.
            if ( $og_title ) {
                printf( "<meta name=\"twitter:title\" content=\"%s\">\n", esc_attr( $og_title ) );
            }
            if ( $description ) {
                printf( "<meta name=\"twitter:description\" content=\"%s\">\n", esc_attr( wp_html_excerpt( $description, 200, '' ) ) );
            }
            if ( $og_image ) {
                printf( "<meta name=\"twitter:image\" content=\"%s\">\n", esc_url( $og_image ) );
            }
        }
        echo "<!-- /Brainwerk SEO Suite -->\n\n";
    }

    private static function auto_excerpt( $post ) {
        if ( ! $post ) {
            return '';
        }
        if ( has_excerpt( $post ) ) {
            return wp_strip_all_tags( get_the_excerpt( $post ) );
        }
        $content = wp_strip_all_tags( strip_shortcodes( $post->post_content ) );
        return mb_substr( trim( preg_replace( '/\s+/', ' ', $content ) ), 0, 200 );
    }
}
