<?php
/**
 * DBA_LATAM_Kaizen — Learning engine for LATAM GeoBot
 *
 * Tracks editor corrections, detects structural repetition,
 * blacklists overused transitions, injects learning context into AI prompt.
 *
 * ALL LATAM-specific: _dba_latam_* meta keys, DBA_LATAM_* class name.
 * Drop into /latam/ folder alongside class-latam-scheduler.php.
 *
 * @since 2.17.0
 */
if ( ! defined( 'ABSPATH' ) ) exit;

class DBA_LATAM_Kaizen {

    const META_ORIGINAL_CONTENT = '_dba_latam_original_content';
    const META_ORIGINAL_TITLE   = '_dba_latam_original_title';
    const META_ORIGINAL_EXCERPT = '_dba_latam_original_excerpt';
    const META_STRUCTURE_HASH   = '_dba_latam_structure_hash';
    const META_OPENER_SIG       = '_dba_latam_opener_sig';
    const CACHE_PREFIX          = 'dba_latam_kaizen_ctx_';
    const CACHE_TTL             = 21600;

    private static $transition_words = array(
        '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',
    );

    /* ── STORE ORIGINAL — call after wp_insert_post in scheduler ── */
    public static function store_original( $post_id, $title, $content, $excerpt = '' ) {
        update_post_meta( $post_id, self::META_ORIGINAL_CONTENT, $content );
        update_post_meta( $post_id, self::META_ORIGINAL_TITLE,   $title );
        if ( $excerpt ) update_post_meta( $post_id, self::META_ORIGINAL_EXCERPT, $excerpt );
        update_post_meta( $post_id, self::META_STRUCTURE_HASH, self::compute_structure_hash( $content ) );
        update_post_meta( $post_id, self::META_OPENER_SIG,     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[] = strtolower(implode(' ', array_slice($w,0,3)));
        }
        return implode('|',$ops);
    }

    /* ── DETECT EDITOR CORRECTIONS (last 5 days) ── */
    public static function detect_corrections( $country_key = '' ) {
        global $wpdb;
        $cw = '';
        if ( $country_key ) $cw = $wpdb->prepare(" AND EXISTS(SELECT 1 FROM {$wpdb->postmeta} pm2 WHERE pm2.post_id=p.ID AND pm2.meta_key='_dba_latam_country' AND pm2.meta_value=%s)", $country_key);
        $ids = $wpdb->get_col("SELECT p.ID FROM {$wpdb->posts} p INNER JOIN {$wpdb->postmeta} pm ON p.ID=pm.post_id AND pm.meta_key='".self::META_ORIGINAL_CONTENT."' WHERE p.post_status IN('publish','draft') AND p.post_date>DATE_SUB(NOW(),INTERVAL 5 DAY) {$cw} ORDER BY p.post_date DESC LIMIT 12");
        $out = array();
        foreach ($ids as $pid) {
            $oc = get_post_meta($pid, self::META_ORIGINAL_CONTENT, true);
            $ot = get_post_meta($pid, self::META_ORIGINAL_TITLE, true);
            $cc = get_post_field('post_content',$pid);
            $ct = get_the_title($pid);
            $city = get_post_meta($pid,'_dba_latam_city',true)?:"#{$pid}";
            $co = get_post_meta($pid,'_dba_latam_country',true)?:'';
            if ($ot && $ot!==$ct) $out[] = array('post_id'=>$pid,'city'=>$city,'country'=>$co,'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,'city'=>$city,'country'=>$co,'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,'city'=>$city,'country'=>$co,'type'=>'h2_change','detail'=>'H2: '.count($oh[0]).'→'.count($ch[0]));
            }
        }
        return $out;
    }

    /* ── GET LEARNING CONTEXT — inject into system prompt ── */
    public static function get_learning_context( $country_key = '' ) {
        $ck = self::CACHE_PREFIX.($country_key?:'all');
        $c = get_transient($ck);
        if (false!==$c) return $c;
        $corrections = self::detect_corrections($country_key);
        $overused = self::get_overused_transitions($country_key);
        $variety = self::check_structural_variety_global($country_key);
        if (empty($corrections)&&empty($overused)&&empty($variety)) { set_transient($ck,'',self::CACHE_TTL); return ''; }
        $ctx = "\n\n── KAIZEN LEARNING (editor corrections on recent LATAM posts) ──\n";
        if (!empty($corrections)) {
            $ctx .= "Editorial corrections — LEARN and apply:\n";
            foreach (array_slice($corrections,0,10) as $co) {
                $ctx .= '  '.strtoupper(str_replace('_',' ',$co['type']))." [{$co['city']}]: {$co['detail']}\n";
            }
        }
        if (!empty($overused)) { $ctx .= "\nBLACKLISTED TRANSITIONS (≥5× in last 10 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 ── */
    public static function get_overused_transitions( $country_key = '' ) {
        global $wpdb;
        $cw='';
        if($country_key) $cw=$wpdb->prepare(" AND EXISTS(SELECT 1 FROM {$wpdb->postmeta} pm2 WHERE pm2.post_id=p.ID AND pm2.meta_key='_dba_latam_country' AND pm2.meta_value=%s)",$country_key);
        $ids=$wpdb->get_col("SELECT p.ID FROM {$wpdb->posts} p INNER JOIN {$wpdb->postmeta} pm ON p.ID=pm.post_id AND pm.meta_key='_dba_latam_auto_created' 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");
        if(empty($ids)) return array();
        $counts=array();
        foreach($ids as $pid) { $txt=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 CHECK ── */
    public static function check_structural_variety_global( $country_key = '' ) {
        global $wpdb;
        $cw='';
        if($country_key) $cw=$wpdb->prepare(" AND EXISTS(SELECT 1 FROM {$wpdb->postmeta} pm2 WHERE pm2.post_id=p.ID AND pm2.meta_key='_dba_latam_country' AND pm2.meta_value=%s)",$country_key);
        $ids=$wpdb->get_col("SELECT p.ID FROM {$wpdb->posts} p INNER JOIN {$wpdb->postmeta} pm ON p.ID=pm.post_id AND pm.meta_key='_dba_latam_auto_created' WHERE p.post_status IN('publish','draft') {$cw} ORDER BY p.post_date DESC LIMIT 10");
        if(count($ids)<3) return array();
        $warnings=array(); $hashes=array();
        foreach($ids as $pid){ $h=get_post_meta($pid,self::META_STRUCTURE_HASH,true); if($h) $hashes[]=$h; }
        $freq=array_count_values($hashes);
        foreach($freq as $h=>$c){ if($c>=3) $warnings[]="{$c}/".count($ids)." recent articles have IDENTICAL structure ({$h}). VARY layout."; }
        return $warnings;
    }

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