<?php
/**
 * DBA_LuxStrat_Intl_Kaizen — Learning engine for LuxStrat International
 *
 * LANGUAGE-AWARE: every method takes $lang. Meta prefix via
 * DBA_LuxStrat_Intl_Dedupe::meta_prefix($lang) → _dba_luxstrat_{lang}_
 *
 * Works ALONGSIDE DBA_LuxStrat_Intl_Corrections (which reads live posts).
 * Kaizen ADDS: original storage, diff detection, transition blacklisting,
 * structural variety checks.
 *
 * WPML-safe: all queries filter by language-specific meta prefix,
 * so FR corrections never leak into IT prompt and vice-versa.
 *
 * @since 2.17.0
 * @package DamalionBlogAI
 * @subpackage LuxStratIntl
 */
if ( ! defined( 'ABSPATH' ) ) exit;

class DBA_LuxStrat_Intl_Kaizen {

    const CACHE_PREFIX = 'dba_lsi_kaizen_';
    const CACHE_TTL    = 21600; // 6 hours

    /* ── Per-language transition blacklist (EN shared + FR + IT) ── */
    private static $transition_words = array(
        // English
        'moreover','furthermore','additionally','consequently','nevertheless',
        'in addition','as a result','on the other hand','in conclusion',
        'for instance','in particular','notably','significantly',
        'therefore','meanwhile','however','likewise','accordingly',
        'subsequently','henceforth','undoubtedly','interestingly',
        'in contrast','for example','in fact','as such','that said',
        'it is worth noting','it should be noted','needless to say',
        // French
        'cependant','néanmoins','en outre','par conséquent','de plus',
        'toutefois','en revanche','par ailleurs','en effet','ainsi',
        'en particulier','notamment','dès lors','à cet égard',
        'de surcroît','par exemple','en somme','en définitive',
        'il convient de noter','il est important de souligner',
        // Italian
        'tuttavia','inoltre','pertanto','di conseguenza','in particolare',
        'nondimeno','al contrario','in effetti','dunque','ciononostante',
        'ad esempio','in sostanza','vale la pena notare','in definitiva',
        'a tal proposito','per di più','in aggiunta',
    );

    /* ══════════════════════════════════════════════════════════════
     *  META KEY HELPERS — always derived from language prefix
     * ══════════════════════════════════════════════════════════════ */
    private static function pfx( $lang ) {
        return DBA_LuxStrat_Intl_Dedupe::meta_prefix( $lang );
    }
    private static function key_original_content( $lang ) { return self::pfx( $lang ) . 'original_content'; }
    private static function key_original_title( $lang )   { return self::pfx( $lang ) . 'original_title'; }
    private static function key_original_excerpt( $lang )  { return self::pfx( $lang ) . 'original_excerpt'; }
    private static function key_structure_hash( $lang )    { return self::pfx( $lang ) . 'structure_hash'; }
    private static function key_opener_sig( $lang )        { return self::pfx( $lang ) . 'opener_sig'; }

    /* ══════════════════════════════════════════════════════════════
     *  STORE ORIGINAL — call after wp_insert_post in generator
     * ══════════════════════════════════════════════════════════════ */
    public static function store_original( $lang, $post_id, $title, $content, $excerpt = '' ) {
        update_post_meta( $post_id, self::key_original_content( $lang ), $content );
        update_post_meta( $post_id, self::key_original_title( $lang ),   $title );
        if ( $excerpt ) {
            update_post_meta( $post_id, self::key_original_excerpt( $lang ), $excerpt );
        }
        update_post_meta( $post_id, self::key_structure_hash( $lang ), self::compute_structure_hash( $content ) );
        update_post_meta( $post_id, self::key_opener_sig( $lang ),     self::compute_opener_signature( $content ) );
    }

    /* ── STRUCTURE FINGERPRINT ── */
    public static function compute_structure_hash( $html ) {
        preg_match_all( '/<h2[^>]*>(.*?)<\/h2>/si', $html, $h2s );
        $h2c = count( $h2s[0] );
        $sections = preg_split( '/<h2[^>]*>/si', $html );
        $pp = array();
        foreach ( $sections as $i => $sec ) {
            if ( $i === 0 && $h2c > 0 ) continue;
            preg_match_all( '/<p[^>]*>/si', $sec, $ps );
            $pp[] = count( $ps[0] );
        }
        $avg = 0;
        preg_match_all( '/<p[^>]*>(.*?)<\/p>/si', $html, $ap );
        if ( ! empty( $ap[1] ) ) {
            $ls = array_map( function( $p ) { return str_word_count( strip_tags( $p ) ); }, $ap[1] );
            $avg = count( $ls ) ? intval( array_sum( $ls ) / count( $ls ) ) : 0;
        }
        return "h2:{$h2c}|pp:" . implode( '-', $pp ) . "|avg:{$avg}";
    }

    public static function compute_opener_signature( $html ) {
        preg_match_all( '/<h2[^>]*>.*?<\/h2>\s*<p[^>]*>(.*?)<\/p>/si', $html, $m );
        $ops = array();
        foreach ( $m[1] as $fp ) {
            $w = preg_split( '/\s+/', strip_tags( $fp ), 4 );
            $ops[] = mb_strtolower( implode( ' ', array_slice( $w, 0, 3 ) ) );
        }
        return implode( '|', $ops );
    }

    /* ══════════════════════════════════════════════════════════════
     *  DETECT EDITOR CORRECTIONS — language-isolated (14 days)
     * ══════════════════════════════════════════════════════════════ */
    public static function detect_corrections( $lang, $theme_slug = '' ) {
        global $wpdb;
        $prefix   = self::pfx( $lang );
        $orig_key = self::key_original_content( $lang );

        $cw = '';
        if ( $theme_slug ) {
            $cw = $wpdb->prepare(
                " AND EXISTS(SELECT 1 FROM {$wpdb->postmeta} pm2 WHERE pm2.post_id=p.ID AND pm2.meta_key=%s AND pm2.meta_value=%s)",
                $prefix . 'theme', $theme_slug
            );
        }

        $ids = $wpdb->get_col( $wpdb->prepare(
            "SELECT p.ID FROM {$wpdb->posts} p
             INNER JOIN {$wpdb->postmeta} pm ON p.ID=pm.post_id AND pm.meta_key=%s
             WHERE p.post_status IN('publish','draft')
             AND p.post_date > DATE_SUB(NOW(), INTERVAL 14 DAY) {$cw}
             ORDER BY p.post_date DESC LIMIT 10",
            $orig_key
        ) );

        $out = array();
        foreach ( $ids as $pid ) {
            $oc    = get_post_meta( $pid, self::key_original_content( $lang ), true );
            $ot    = get_post_meta( $pid, self::key_original_title( $lang ), true );
            $cc    = get_post_field( 'post_content', $pid );
            $ct    = get_the_title( $pid );
            $label = get_post_meta( $pid, $prefix . 'theme_label', true ) ?: '';

            if ( $ot && $ot !== $ct ) {
                $out[] = array( 'post_id' => $pid, 'theme' => $label, 'type' => 'title', 'detail' => "'{$ot}' → '{$ct}'" );
            }
            if ( $oc ) {
                $ow  = str_word_count( strip_tags( $oc ) );
                $cw2 = str_word_count( strip_tags( $cc ) );
                if ( $ow > 0 && abs( $cw2 - $ow ) / $ow * 100 > 5 ) {
                    $d = $cw2 > $ow ? 'expanded' : 'trimmed';
                    $out[] = array( 'post_id' => $pid, 'theme' => $label, 'type' => 'content_' . $d,
                        'detail' => "{$ow}→{$cw2} words ({$d} " . round( abs( $cw2 - $ow ) / $ow * 100 ) . "%)" );
                }
                preg_match_all( '/<h2[^>]*>/si', $oc, $oh );
                preg_match_all( '/<h2[^>]*>/si', $cc, $ch );
                if ( count( $oh[0] ) !== count( $ch[0] ) ) {
                    $out[] = array( 'post_id' => $pid, 'theme' => $label, 'type' => 'h2_change',
                        'detail' => 'H2: ' . count( $oh[0] ) . '→' . count( $ch[0] ) );
                }
            }
        }
        return $out;
    }

    /* ══════════════════════════════════════════════════════════════
     *  LEARNING CONTEXT — inject into system prompt per language
     * ══════════════════════════════════════════════════════════════ */
    public static function get_learning_context( $lang, $theme_slug = '' ) {
        $ck = self::CACHE_PREFIX . $lang . '_' . ( $theme_slug ?: 'all' );
        $c  = get_transient( $ck );
        if ( false !== $c ) return $c;

        $corrections = self::detect_corrections( $lang, $theme_slug );
        $overused    = self::get_overused_transitions( $lang );
        $variety     = self::check_structural_variety( $lang );

        if ( empty( $corrections ) && empty( $overused ) && empty( $variety ) ) {
            set_transient( $ck, '', self::CACHE_TTL );
            return '';
        }

        $lu = strtoupper( $lang );
        $ctx = "\n\n── KAIZEN LEARNING (editor corrections on recent {$lu} posts) ──\n";

        if ( ! empty( $corrections ) ) {
            $ctx .= "Editorial corrections detected — LEARN and apply:\n";
            foreach ( array_slice( $corrections, 0, 10 ) as $co ) {
                $ctx .= '  ' . strtoupper( str_replace( '_', ' ', $co['type'] ) ) . " [{$co['theme']}]: {$co['detail']}\n";
            }
        }
        if ( ! empty( $overused ) ) {
            $ctx .= "\nBLACKLISTED TRANSITIONS (≥5× in last 10 {$lu} posts — DO NOT USE):\n  ✗ " . implode( ', ✗ ', $overused ) . "\n";
        }
        if ( ! empty( $variety ) ) {
            $ctx .= "\nSTRUCTURAL WARNINGS:\n";
            foreach ( $variety as $w ) $ctx .= "  ⚠ {$w}\n";
        }

        set_transient( $ck, $ctx, self::CACHE_TTL );
        return $ctx;
    }

    /* ── OVERUSED TRANSITIONS per language ── */
    public static function get_overused_transitions( $lang ) {
        global $wpdb;
        $prefix = self::pfx( $lang );

        $ids = $wpdb->get_col( $wpdb->prepare(
            "SELECT p.ID FROM {$wpdb->posts} p
             INNER JOIN {$wpdb->postmeta} pm ON p.ID=pm.post_id AND pm.meta_key=%s
             WHERE p.post_status IN('publish','draft')
             AND p.post_date > DATE_SUB(NOW(), INTERVAL 30 DAY)
             ORDER BY p.post_date DESC LIMIT 10",
            $prefix . 'auto_created'
        ) );
        if ( empty( $ids ) ) return array();

        $counts = array();
        foreach ( $ids as $pid ) {
            $txt = mb_strtolower( strip_tags( get_post_field( 'post_content', $pid ) ) );
            foreach ( self::$transition_words as $tw ) {
                $c = substr_count( $txt, $tw );
                if ( $c > 0 ) $counts[ $tw ] = ( $counts[ $tw ] ?? 0 ) + $c;
            }
        }
        $out = array();
        foreach ( $counts as $tw => $t ) { if ( $t >= 5 ) $out[] = $tw; }
        return $out;
    }

    /* ── STRUCTURAL VARIETY per language ── */
    public static function check_structural_variety( $lang ) {
        global $wpdb;
        $prefix   = self::pfx( $lang );
        $hash_key = self::key_structure_hash( $lang );

        $ids = $wpdb->get_col( $wpdb->prepare(
            "SELECT p.ID FROM {$wpdb->posts} p
             INNER JOIN {$wpdb->postmeta} pm ON p.ID=pm.post_id AND pm.meta_key=%s
             WHERE p.post_status IN('publish','draft')
             ORDER BY p.post_date DESC LIMIT 10",
            $prefix . 'auto_created'
        ) );
        if ( count( $ids ) < 3 ) return array();

        $hashes = array();
        foreach ( $ids as $pid ) { $h = get_post_meta( $pid, $hash_key, true ); if ( $h ) $hashes[] = $h; }
        $warnings = array();
        $freq = array_count_values( $hashes );
        foreach ( $freq as $h => $c ) {
            if ( $c >= 3 ) $warnings[] = "{$c}/" . count( $ids ) . " recent " . strtoupper( $lang ) . " articles have IDENTICAL structure ({$h}). VARY layout.";
        }
        return $warnings;
    }

    /* ── CACHE INVALIDATION ── */
    public static function invalidate_cache( $lang = '' ) {
        global $wpdb;
        $pattern = self::CACHE_PREFIX . ( $lang ? $lang . '_' : '' );
        $wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_{$pattern}%' OR option_name LIKE '_transient_timeout_{$pattern}%'" );
    }
}
