<?php
/**
 * LuxStrat International — Universal Content Validator
 *
 * One class for ALL languages. Reads slop phrases, placeholders,
 * language markers, and passive voice regex from the language config.
 *
 * @package DamalionBlogAI
 * @subpackage LuxStratIntl
 */

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

class DBA_LuxStrat_Intl_Validator {

    /**
     * Validate generated content against quality criteria.
     *
     * @param  string $lang        Language code.
     * @param  array  $lang_config Language configuration array.
     * @param  array  $data        Generated content { title, content, excerpt, theme }.
     * @return array               { valid, errors, warnings }
     */
    public static function validate( $lang, $lang_config, $data ) {
        $errors   = array();
        $warnings = array();

        $title   = isset( $data['title'] )   ? trim( $data['title'] )   : '';
        $content = isset( $data['content'] ) ? trim( $data['content'] ) : '';
        $excerpt = isset( $data['excerpt'] ) ? trim( $data['excerpt'] ) : '';
        $theme   = isset( $data['theme'] )   ? trim( $data['theme'] )   : '';

        // ── Title checks ──
        if ( empty( $title ) ) {
            $errors[] = 'Title is empty.';
        } elseif ( mb_strlen( $title ) < 30 ) {
            $errors[] = 'Title too short (min 30 chars). Got: ' . mb_strlen( $title );
        } elseif ( mb_strlen( $title ) > 160 ) {
            $warnings[] = 'Title is very long (' . mb_strlen( $title ) . ' chars).';
        }

        // ── Content checks ──
        if ( empty( $content ) ) {
            $errors[] = 'Content is empty.';
        } else {
            $word_count = str_word_count( strip_tags( $content ) );
            $settings   = get_option( 'dba_luxstrat_' . $lang . '_settings', array() );
            $min_words  = ! empty( $settings['word_count_min'] ) ? (int) $settings['word_count_min'] : 1000;
            $max_words  = ! empty( $settings['word_count_max'] ) ? (int) $settings['word_count_max'] : 1800;

            $soft_min = (int) round( $min_words * 0.92 );
            if ( $word_count < $soft_min ) {
                $errors[] = "Word count too low: {$word_count} (minimum: {$min_words}, hard floor: {$soft_min}).";
            } elseif ( $word_count < $min_words ) {
                $warnings[] = "Word count slightly below target: {$word_count} (target: {$min_words}).";
            }
            if ( $word_count > $max_words + 300 ) {
                $warnings[] = "Word count high: {$word_count} (target max: {$max_words}).";
            }

            if ( substr_count( $content, '<h2' ) < 2 ) {
                $errors[] = 'Content must have at least 2 H2 headings.';
            }
            if ( substr_count( $content, '<p' ) < 3 ) {
                $errors[] = 'Content must have at least 3 paragraphs.';
            }

            // Slop phrases (from language config)
            $slop = ! empty( $lang_config['slop_phrases'] ) ? $lang_config['slop_phrases'] : array();
            $content_lower = mb_strtolower( $content );
            foreach ( $slop as $phrase ) {
                if ( mb_strpos( $content_lower, $phrase ) !== false ) {
                    $warnings[] = 'AI slop phrase detected: "' . $phrase . '"';
                }
            }

            // Placeholders (from language config)
            $placeholders = ! empty( $lang_config['placeholders'] ) ? $lang_config['placeholders'] : array( '[INSERT', '[TODO', '{{', '}}', 'Lorem ipsum' );
            foreach ( $placeholders as $ph ) {
                if ( stripos( $content, $ph ) !== false ) {
                    $errors[] = 'Placeholder text found: "' . $ph . '"';
                }
            }

            // Language markers check (is content actually in the right language?)
            if ( ! empty( $lang_config['language_markers'] ) ) {
                $hits = 0;
                foreach ( $lang_config['language_markers'] as $marker ) {
                    if ( mb_stripos( $content, $marker ) !== false ) $hits++;
                }
                $min_hits = ! empty( $lang_config['language_markers_min'] ) ? $lang_config['language_markers_min'] : 5;
                if ( $hits < $min_hits ) {
                    $warnings[] = 'Content may not be in ' . $lang_config['label'] . ' (' . $hits . '/' . count( $lang_config['language_markers'] ) . ' markers found).';
                }
            }
        }

        // ── Excerpt check ──
        if ( empty( $excerpt ) ) {
            $warnings[] = 'Excerpt is empty.';
        } elseif ( mb_strlen( $excerpt ) > 300 ) {
            $warnings[] = 'Excerpt is long (' . mb_strlen( $excerpt ) . ' chars).';
        }

        // ── Theme check ──
        if ( empty( $theme ) ) {
            $errors[] = 'Theme slug is missing.';
        } else {
            $themes = ! empty( $lang_config['themes'] ) ? $lang_config['themes'] : array();
            if ( ! isset( $themes[ $theme ] ) ) {
                $errors[] = 'Unknown theme slug: "' . $theme . '" for language ' . $lang;
            }
        }

        // ── Duplicate title check ──
        if ( ! empty( $title ) && DBA_LuxStrat_Intl_Dedupe::title_is_duplicate( $lang, $title ) ) {
            $errors[] = 'Title too similar to a recent post in this language (last 90 days).';
        }

        return array(
            'valid'    => empty( $errors ),
            'errors'   => $errors,
            'warnings' => $warnings,
        );
    }

    /**
     * Validate writing style: passive voice, sentence length, transition words.
     * Uses language-specific passive regex and transitions from config.
     *
     * @param  string $lang        Language code.
     * @param  array  $lang_config Language configuration.
     * @param  array  $data        Generated content with 'content' key.
     * @return array               Error messages (empty if all checks pass).
     */
    public static function validate_style( $lang, $lang_config, $data ) {
        $errors = array();

        if ( empty( $data['content'] ) ) return $errors;

        $text = strip_tags( $data['content'] );

        $sentences = preg_split( '/(?<=[.!?])\s+/', $text, -1, PREG_SPLIT_NO_EMPTY );
        $sentences = array_filter( $sentences, function( $s ) {
            return mb_strlen( trim( $s ) ) > 10;
        } );
        $sentences      = array_values( $sentences );
        $sentence_count = count( $sentences );

        if ( $sentence_count < 5 ) return $errors;

        $log_prefix = 'LuxStrat[' . $lang . ']';

        // ── 1. Passive voice (threshold: 10%) ──
        $passive_regex = ! empty( $lang_config['passive_regex'] )
            ? $lang_config['passive_regex']
            // Fallback: English passive
            : '/\b(is|are|was|were|been|being|be)\s+(\w+ly\s+)?((?:[a-z]+ed|built|held|made|set|run|done|given|known|seen|shown|found|kept|meant|paid|sold|told|written|chosen|driven|spoken|taken|broken|frozen|gotten|proven|worn|torn|sworn|born|borne|drawn|grown|thrown|begun|drunk|shrunk|sunk|struck|stuck)\b)/i';

        $passive_count = 0;
        foreach ( $sentences as $s ) {
            if ( preg_match( $passive_regex, $s ) ) $passive_count++;
        }
        $passive_pct = round( ( $passive_count / $sentence_count ) * 100, 1 );

        if ( $passive_pct > 10 ) {
            $errors[] = 'Passive voice is at ' . $passive_pct . '% (' . $passive_count . '/' . $sentence_count . '). Target: under 10%.';
        }

        // ── 2. Sentence length (threshold: 25% over 20 words) ──
        $long_count = 0;
        foreach ( $sentences as $s ) {
            if ( str_word_count( trim( $s ) ) > 20 ) $long_count++;
        }
        $long_pct = round( ( $long_count / $sentence_count ) * 100, 1 );

        if ( $long_pct > 25 ) {
            $errors[] = 'Long sentences: ' . $long_pct . '% exceed 20 words. Target: under 25%.';
        }

        // ── 3. Transition words (threshold: 30%) ──
        $transitions = ! empty( $lang_config['transitions'] ) ? $lang_config['transitions'] : array();
        if ( ! empty( $transitions ) ) {
            $pattern = '/\b(' . implode( '|', array_map( function( $t ) {
                return preg_quote( $t, '/' );
            }, $transitions ) ) . ')\b/iu';

            $transition_count = 0;
            foreach ( $sentences as $s ) {
                if ( preg_match( $pattern, $s ) ) $transition_count++;
            }
            $transition_pct = round( ( $transition_count / $sentence_count ) * 100, 1 );

            if ( $transition_pct < 30 ) {
                $errors[] = 'Transition words in only ' . $transition_pct . '% of sentences. Target: at least 30%.';
            }

            error_log( $log_prefix . ' style — Passive: ' . $passive_pct . '% | Long: ' . $long_pct . '% | Transitions: ' . $transition_pct . '%' );
        } else {
            error_log( $log_prefix . ' style — Passive: ' . $passive_pct . '% | Long: ' . $long_pct . '% | No transitions defined' );
        }

        return $errors;
    }
}
