<?php
class ChairmanConsensusEngineV49 {
    private $db;
    public function __construct(mysqli $db){$this->db=$db;@$db->set_charset('utf8mb4');}
    private function q($s){return "'".$this->db->real_escape_string((string)$s)."'";}
    private function n($v,$d=0){return is_numeric($v)?(float)$v:$d;}
    private function clamp($v,$a=0,$b=100){return max($a,min($b,$v));}
    private function rows($sql){$a=array();$r=@$this->db->query($sql);if($r){while($x=$r->fetch_assoc())$a[]=$x;}return $a;}
    private function exists($t){$r=@$this->db->query("SHOW TABLES LIKE ".$this->q($t));return $r&&$r->num_rows>0;}
    private function latest($table,$date,$venue=''){
        if(!$this->exists($table))return '';
        $w="race_date=".$this->q($date).($venue!==''?" AND venue=".$this->q($venue):'');
        $r=@$this->db->query("SELECT run_key FROM {$table} WHERE {$w} ORDER BY created_at DESC,id DESC LIMIT 1");
        return ($r&&($x=$r->fetch_assoc()))?(string)$x['run_key']:'';
    }
    public function ensureTables(){
        $this->db->query("CREATE TABLE IF NOT EXISTS wr_chairman_consensus_v49 (
          id INT AUTO_INCREMENT PRIMARY KEY, consensus_key VARCHAR(700) NOT NULL, run_key VARCHAR(80) NOT NULL,
          source_v44_run VARCHAR(80) NOT NULL DEFAULT '', source_v47_run VARCHAR(80) NOT NULL DEFAULT '', source_v48_run VARCHAR(80) NOT NULL DEFAULT '',
          race_date DATE NULL, venue VARCHAR(80) NOT NULL DEFAULT '', race_num INT NOT NULL DEFAULT 0,
          horse_num VARCHAR(20) NOT NULL DEFAULT '', horse_name VARCHAR(180) NOT NULL DEFAULT '',
          v44_score DECIMAL(10,4) NOT NULL DEFAULT 0, v47_score DECIMAL(10,4) NOT NULL DEFAULT 0, v48_confidence DECIMAL(10,4) NOT NULL DEFAULT 0,
          support_count INT NOT NULL DEFAULT 0, warning_count INT NOT NULL DEFAULT 0, contradiction_count INT NOT NULL DEFAULT 0,
          consensus_pct DECIMAL(10,4) NOT NULL DEFAULT 0, stability_score DECIMAL(10,4) NOT NULL DEFAULT 0,
          chairman_final_score DECIMAL(10,4) NOT NULL DEFAULT 0, final_rank INT NOT NULL DEFAULT 0,
          final_tag VARCHAR(80) NOT NULL DEFAULT 'WATCH', final_action VARCHAR(30) NOT NULL DEFAULT 'WATCH',
          heat_value DECIMAL(10,4) NOT NULL DEFAULT 0, final_reason TEXT NULL, payload_json LONGTEXT NULL,
          created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
          UNIQUE KEY uk_v49(consensus_key), KEY idx_v49_race(race_date,venue,race_num), KEY idx_v49_run(run_key), KEY idx_v49_score(chairman_final_score)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
        $this->db->query("CREATE TABLE IF NOT EXISTS wr_chairman_race_consensus_v49 (
          id INT AUTO_INCREMENT PRIMARY KEY, summary_key VARCHAR(700) NOT NULL, run_key VARCHAR(80) NOT NULL,
          race_date DATE NULL, venue VARCHAR(80) NOT NULL DEFAULT '', race_num INT NOT NULL DEFAULT 0,
          race_stability_index DECIMAL(10,4) NOT NULL DEFAULT 0, race_consensus_pct DECIMAL(10,4) NOT NULL DEFAULT 0,
          race_clarity VARCHAR(40) NOT NULL DEFAULT 'LOW', chairman_banker VARCHAR(20) NOT NULL DEFAULT '',
          q_top2 VARCHAR(120) NOT NULL DEFAULT '', trio_top4 VARCHAR(180) NOT NULL DEFAULT '', value_horses VARCHAR(180) NOT NULL DEFAULT '', avoid_horses VARCHAR(220) NOT NULL DEFAULT '',
          final_summary TEXT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
          UNIQUE KEY uk_v49_sum(summary_key), KEY idx_v49_sum_race(race_date,venue,race_num), KEY idx_v49_sum_run(run_key)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
        $this->db->query("CREATE TABLE IF NOT EXISTS wr_chairman_consensus_run_log_v49 (
          id INT AUTO_INCREMENT PRIMARY KEY, run_key VARCHAR(80) NOT NULL, race_date DATE NULL, venue VARCHAR(80) NOT NULL DEFAULT '',
          status VARCHAR(30) NOT NULL DEFAULT 'DONE', horse_rows INT NOT NULL DEFAULT 0, race_rows INT NOT NULL DEFAULT 0,
          message TEXT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
          KEY idx_v49_log(run_key), KEY idx_v49_log_date(race_date,venue)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
    }
    private function confScore($s){$m=array('VERY_HIGH'=>92,'HIGH'=>78,'MEDIUM'=>62,'LOW'=>45,'VERY_LOW'=>28);return isset($m[$s])?$m[$s]:50;}
    private function tag($rank,$score,$cons,$stab,$risk,$warn,$contra){
        if($rank===1&&$score>=76&&$cons>=78&&$stab>=70)return 'KING';
        if($rank===1&&$score>=66&&$cons>=68)return 'MAIN_BANKER';
        if($rank<=2&&$score>=60)return 'TOP_PLACE';
        if($rank<=4&&$score>=53&&$risk<68)return 'VALUE';
        if($rank>=4&&$score>=50&&$cons>=58&&$risk<65)return 'BOMB';
        if($warn>=4||$contra>=3||$risk>=78)return 'SKIP';
        return 'WATCH';
    }
    private function action($tag){if(in_array($tag,array('KING','MAIN_BANKER'),true))return 'BUY';if(in_array($tag,array('TOP_PLACE','VALUE'),true))return 'COVER';if($tag==='SKIP')return 'SKIP';return 'WATCH';}
    public function build($date,$venue=''){
        $this->ensureTables();
        $r44=$this->latest('wr_chairman_production_score_v44',$date,$venue);
        $r47=$this->latest('wr_chairman_pre_race_run_log_v47',$date,$venue);
        $r48=$this->latest('wr_chairman_explain_run_log_v48',$date,$venue);
        if($r44===''||$r47===''||$r48==='')return array('status'=>'SOURCE_EMPTY','message'=>'Build V44, V47 and V48 first.','v44_run'=>$r44,'v47_run'=>$r47,'v48_run'=>$r48);
        $vw=$venue!==''?" AND venue=".$this->q($venue):'';
        $a44=$this->rows("SELECT * FROM wr_chairman_production_score_v44 WHERE race_date=".$this->q($date)." {$vw} AND run_key=".$this->q($r44));
        $a47=$this->rows("SELECT * FROM wr_chairman_pre_race_decision_v47 WHERE race_date=".$this->q($date)." {$vw} AND run_key=".$this->q($r47));
        $a48=$this->rows("SELECT * FROM wr_chairman_explanation_v48 WHERE race_date=".$this->q($date)." {$vw} AND run_key=".$this->q($r48));
        $m44=$m48=array();foreach($a44 as $r)$m44[(int)$r['race_num'].'|'.(int)$r['horse_num']]=$r;foreach($a48 as $r)$m48[(int)$r['race_num'].'|'.(int)$r['horse_num']]=$r;
        $run=date('YmdHis').'_'.mt_rand(1000,9999);$by=array();$hc=0;$rc=0;
        foreach($a47 as $r){
            $k=(int)$r['race_num'].'|'.(int)$r['horse_num'];$x44=isset($m44[$k])?$m44[$k]:array();$x48=isset($m48[$k])?$m48[$k]:array();
            $v44=$this->n(isset($x44['calibrated_score'])?$x44['calibrated_score']:0);$v47=$this->n($r['ensemble_score']);$v48=$this->confScore(isset($x48['confidence_label'])?$x48['confidence_label']:'LOW');
            $sup=(int)(isset($x48['support_count'])?$x48['support_count']:0);$warn=(int)(isset($x48['warning_count'])?$x48['warning_count']:0);$con=(int)(isset($x48['contradiction_count'])?$x48['contradiction_count']:0);$risk=$this->n(isset($r['risk_score'])?$r['risk_score']:0);
            $sr=(int)(isset($x44['race_rank'])?$x44['race_rank']:99);$pr=(int)$r['pre_race_rank'];$agrRank=max(0,100-abs($sr-$pr)*11);$agrScore=max(0,100-abs($v44-$v47)*4.2);
            $cons=$this->clamp($agrRank*.35+$agrScore*.35+$v48*.20+min(100,$sup*12)*.10-$warn*4-$con*6);
            $stab=$this->clamp($v48*.40+(100-$risk)*.30+$agrRank*.20+min(100,$sup*10)*.10-$warn*3.5-$con*4.5);
            $final=$this->clamp($v44*.28+$v47*.42+$v48*.15+$cons*.10+$stab*.05-$risk*.08-$warn*1.4-$con*2.2);
            $rn=(int)$r['race_num'];if(!isset($by[$rn]))$by[$rn]=array();$by[$rn][]=array('r'=>$r,'v44'=>$v44,'v47'=>$v47,'v48'=>$v48,'sup'=>$sup,'warn'=>$warn,'con'=>$con,'risk'=>$risk,'cons'=>$cons,'stab'=>$stab,'final'=>$final);
        }
        $this->db->begin_transaction();
        foreach($by as $rn=>$rows){
            usort($rows,function($a,$b){return $a['final']==$b['final']?($a['cons']<$b['cons']?1:-1):($a['final']<$b['final']?1:-1);});
            foreach($rows as $i=>&$x){$rank=$i+1;$tag=$this->tag($rank,$x['final'],$x['cons'],$x['stab'],$x['risk'],$x['warn'],$x['con']);$act=$this->action($tag);$heat=$this->clamp($x['final']*.55+$x['cons']*.30+$x['stab']*.15);$reason='V49 Consensus｜V44 '.number_format($x['v44'],1).'｜V47 '.number_format($x['v47'],1).'｜V48Conf '.number_format($x['v48'],1).'｜Consensus '.number_format($x['cons'],1).'｜RSI '.number_format($x['stab'],1).'｜Risk '.number_format($x['risk'],1).'｜Final '.number_format($x['final'],1).'｜Tag '.$tag.'｜未使用賽果。';$key=sha1($run.'|V49|'.$date.'|'.$venue.'|'.$rn.'|'.$x['r']['horse_num']);$payload=json_encode(array('pre_race_only'=>true,'results_used'=>false,'support'=>$x['sup'],'warning'=>$x['warn'],'contradiction'=>$x['con']),JSON_UNESCAPED_UNICODE);
                $sql="INSERT INTO wr_chairman_consensus_v49 (consensus_key,run_key,source_v44_run,source_v47_run,source_v48_run,race_date,venue,race_num,horse_num,horse_name,v44_score,v47_score,v48_confidence,support_count,warning_count,contradiction_count,consensus_pct,stability_score,chairman_final_score,final_rank,final_tag,final_action,heat_value,final_reason,payload_json) VALUES (".$this->q($key).",".$this->q($run).",".$this->q($r44).",".$this->q($r47).",".$this->q($r48).",".$this->q($date).",".$this->q($venue).",{$rn},".$this->q($x['r']['horse_num']).",".$this->q($x['r']['horse_name']).",{$x['v44']},{$x['v47']},{$x['v48']},{$x['sup']},{$x['warn']},{$x['con']},{$x['cons']},{$x['stab']},{$x['final']},{$rank},".$this->q($tag).",".$this->q($act).",{$heat},".$this->q($reason).",".$this->q($payload).")";$this->db->query($sql);$x['tag']=$tag;$x['act']=$act;$x['heat']=$heat;$hc++;}
            unset($x);$top=$rows[0];$top2=array_slice($rows,0,2);$top4=array_slice($rows,0,4);$q=array();foreach($top2 as $x)$q[]=$x['r']['horse_num'];$trio=array();foreach($top4 as $x)$trio[]=$x['r']['horse_num'];$value=$avoid=array();foreach($rows as $x){if(in_array($x['tag'],array('VALUE','BOMB'),true))$value[]=$x['r']['horse_num'];if($x['tag']==='SKIP')$avoid[]=$x['r']['horse_num'];}
            $ac=$as=0;foreach($top4 as $x){$ac+=$x['cons'];$as+=$x['stab'];}$ac=count($top4)?$ac/count($top4):0;$as=count($top4)?$as/count($top4):0;$clarity=($top['tag']==='KING'&&$ac>=72&&$as>=68)?'VERY_CLEAR':((in_array($top['tag'],array('KING','MAIN_BANKER'),true)&&$ac>=62)?'CLEAR':($ac>=50?'MIXED':'LOW'));
            $summary='V49 Final：R'.$rn.'｜膽 #'.$top['r']['horse_num'].'｜Tag '.$top['tag'].'｜Final '.number_format($top['final'],1).'｜Consensus '.number_format($ac,1).'｜RSI '.number_format($as,1).'｜Q '.implode(',',$q).'｜Top4 '.implode(',',$trio).'｜Value '.implode(',',array_slice($value,0,3)).'｜Avoid '.implode(',',array_slice($avoid,0,6)).'｜未使用賽果。';$skey=sha1($run.'|SUM|'.$date.'|'.$venue.'|'.$rn);
            $sql="INSERT INTO wr_chairman_race_consensus_v49 (summary_key,run_key,race_date,venue,race_num,race_stability_index,race_consensus_pct,race_clarity,chairman_banker,q_top2,trio_top4,value_horses,avoid_horses,final_summary) VALUES (".$this->q($skey).",".$this->q($run).",".$this->q($date).",".$this->q($venue).",{$rn},{$as},{$ac},".$this->q($clarity).",".$this->q($top['r']['horse_num']).",".$this->q(implode(',',$q)).",".$this->q(implode(',',$trio)).",".$this->q(implode(',',array_slice($value,0,3))).",".$this->q(implode(',',array_slice($avoid,0,6))).",".$this->q($summary).")";$this->db->query($sql);$rc++;
        }
        $msg='Built V49 Consensus: horses '.$hc.' | races '.$rc.' | pre-race only';$this->db->query("INSERT INTO wr_chairman_consensus_run_log_v49 (run_key,race_date,venue,status,horse_rows,race_rows,message) VALUES (".$this->q($run).",".$this->q($date).",".$this->q($venue).",'DONE',{$hc},{$rc},".$this->q($msg).")");$this->db->commit();
        return array('status'=>'BUILT','run_key'=>$run,'race_date'=>$date,'venue'=>$venue,'pre_race_only'=>true,'results_used'=>false,'horse_rows'=>$hc,'race_rows'=>$rc,'message'=>$msg);
    }
    public function latestData($date,$venue=''){
        $this->ensureTables();$run=$this->latest('wr_chairman_consensus_run_log_v49',$date,$venue);if($run==='')return array('status'=>'EMPTY','pre_race_only'=>true,'results_used'=>false,'summary'=>array(),'ranking'=>array());$w="race_date=".$this->q($date)." AND run_key=".$this->q($run).($venue!==''?" AND venue=".$this->q($venue):'');return array('status'=>'OK','run_key'=>$run,'pre_race_only'=>true,'results_used'=>false,'summary'=>$this->rows("SELECT * FROM wr_chairman_race_consensus_v49 WHERE {$w} ORDER BY race_num"),'ranking'=>$this->rows("SELECT * FROM wr_chairman_consensus_v49 WHERE {$w} ORDER BY race_num,final_rank"));
    }
}
