<?php

declare(strict_types=1);

// B test harness gate timing: metadata/natural SQL then old/new connection
// SELECT 1. No business HTTP, DML, credentials, names or row values emitted.
if ($argc!==2 || $argv[1]!=='--profile-b-readonly-gates') {
    fwrite(STDERR,"Explicit Bill B read-only gate profile required\n");
    exit(2);
}
$phase='runtime';
$start=microtime(true);
$timing=[];
try {
    $root='/tmp/zhct-http-store-mysql.dQTTBP';
    $cmd=str_replace("\0",' ',(string)file_get_contents('/proc/10001/cmdline'));
    if (strpos($cmd,' -S 127.0.0.1:18081 ')===false
        || strpos($cmd,$root.'/public')===false
        || substr_count($cmd,' -S ')!==1) {
        throw new RuntimeException('Wrong B isolated process');
    }
    $load=static function(string $file): array { return require $file; };
    $local=$load('/workspace/zhct/zhctproject/store/application/config/local/database.php');
    $runtime=$load($root.'/application/database.php');
    foreach (['hostname','database','username','password'] as $field) {
        if (!isset($local[$field],$runtime[$field])
            || $local[$field]!==$runtime[$field]) {
            throw new RuntimeException('Wrong code-local DB');
        }
    }
    if (($runtime['type']??null)!=='mysql'
        || (int)($local['hostport']??3306)
            !==(int)($runtime['hostport']??3306)) {
        throw new RuntimeException('Wrong B MySQL mode');
    }
    $timing['runtime_config_ms']=(int)round((microtime(true)-$start)*1000);
    $open=static function() use ($local): PDO {
        return new PDO('mysql:host='.$local['hostname'].';port='.
            (int)($local['hostport']??3306).';dbname='.$local['database']
            .';charset=utf8mb4',(string)$local['username'],
            (string)$local['password'],[
                PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_EMULATE_PREPARES=>false,
                PDO::ATTR_DEFAULT_FETCH_MODE=>PDO::FETCH_ASSOC,
                PDO::ATTR_TIMEOUT=>8,
            ]);
    };
    $phase='initial-connect';
    $t=microtime(true);
    $db=$open();
    if (strpos((string)$db->query('SELECT VERSION()')->fetchColumn(),'5.6.')!==0) {
        throw new RuntimeException('Not code-local MySQL5.6');
    }
    $timing['initial_connect_version_ms']=(int)round((microtime(true)-$t)*1000);
    $schema=(string)$local['database'];
    $scalar=static function(PDO $conn,string $sql,array $args=[]): int {
        $stmt=$conn->prepare($sql);
        $stmt->execute($args);
        return (int)$stmt->fetchColumn();
    };
    $phase='metadata';
    $t=microtime(true);
    $columns=$db->prepare('SELECT COLUMN_NAME,IS_NULLABLE,COLUMN_DEFAULT'
        .' FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=? AND TABLE_NAME=?');
    foreach (['ydy_user','ydy_role','ydy_user_role','ydy_role_menu',
        'ydy_user_data'] as $table) {
        $columns->execute([$schema,$table]);
        if (!$columns->fetchAll(PDO::FETCH_ASSOC)) {
            throw new RuntimeException('Permission metadata missing');
        }
        $scalar($db,'SELECT COUNT(*) FROM information_schema.TRIGGERS'
            .' WHERE TRIGGER_SCHEMA=? AND EVENT_OBJECT_TABLE=?',
            [$schema,$table]);
        $scalar($db,'SELECT COUNT(*) FROM information_schema.KEY_COLUMN_USAGE'
            .' WHERE TABLE_SCHEMA=? AND TABLE_NAME=?'
            .' AND REFERENCED_TABLE_NAME IS NOT NULL',
            [$schema,$table]);
    }
    $index=$db->prepare('SELECT INDEX_NAME,NON_UNIQUE,SEQ_IN_INDEX,COLUMN_NAME'
        .' FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=?'
        .' AND TABLE_NAME=? ORDER BY INDEX_NAME,SEQ_IN_INDEX');
    foreach (['ydy_role','ydy_user_role','ydy_role_menu','ydy_user_data'] as $table) {
        $index->execute([$schema,$table]);
        $index->fetchAll(PDO::FETCH_ASSOC);
    }
    foreach (['ydy_user'=>'account','ydy_role'=>'name',
        'ydy_user_role'=>'create_by','ydy_role_menu'=>'create_by'] as $table=>$column) {
        if ($scalar($db,'SELECT COUNT(*) FROM '.$table.' WHERE '.$column
            .' LIKE ?', ['CDXPARBILL%'])!==0) {
            throw new RuntimeException('Prior Bill marker residue');
        }
    }
    $timing['permission_metadata_ms']=(int)round((microtime(true)-$t)*1000);

    $phase='natural-candidate';
    $t=microtime(true);
    $sql='SELECT r.menu_date menu_date,r.restaurant_id restaurant_id,'
        .' r.meal_times meal_times,r.dishes_uuid dishes_uuid'
        .' FROM ydy_recipes r JOIN ydy_dishes d ON d.uuid=r.dishes_uuid'
        .' JOIN ydy_restaurants st ON st.id=r.restaurant_id'
        .' WHERE d.is_del=1 AND d.status=1 AND d.store_id=10001'
        .' AND d.category BETWEEN 1 AND 6'
        .' AND st.status=1 AND st.is_delete=2'
        .' AND r.meal_times BETWEEN 1 AND 3 AND EXISTS('
        .' SELECT 1 FROM ydy_date_menu dm'
        .' WHERE dm.dishes_uuid=r.dishes_uuid'
        .' AND dm.menu_date=r.menu_date'
        .' AND dm.restaurant_id=r.restaurant_id'
        .' AND dm.meal_times=r.meal_times AND dm.meal_type=3)'
        .' ORDER BY r.menu_date DESC LIMIT 5000';
    $matched=[];
    foreach ($db->query($sql)->fetchAll(PDO::FETCH_ASSOC) as $row) {
        $date=substr((string)$row['menu_date'],0,10);
        $hash=substr(hash('sha256',(string)$row['dishes_uuid'].'|'
            .$date.'|'.(int)$row['restaurant_id'].'|'
            .(int)$row['meal_times']),0,12);
        if ($hash==='5f07d785b0f1') $matched[$hash]=$row;
    }
    if (count($matched)!==1) throw new RuntimeException('Natural target missing');
    $row=reset($matched);
    $date=substr((string)$row['menu_date'],0,10);
    $restaurant=(int)$row['restaurant_id'];
    $meal=(int)$row['meal_times'];
    $timing['natural_candidate_scan_ms']=(int)round((microtime(true)-$t)*1000);

    $phase='source-counts';
    $t=microtime(true);
    $scalar($db,'SELECT COUNT(*) FROM ydy_recipes WHERE menu_date=?'
        .' AND restaurant_id=? AND meal_times=?',[$date,$restaurant,$meal]);
    $scalar($db,'SELECT COUNT(*) FROM ydy_recipes r JOIN ydy_dishes d'
        .' ON d.uuid=r.dishes_uuid WHERE r.menu_date=?'
        .' AND r.restaurant_id=? AND r.meal_times=? AND d.is_del=1',
        [$date,$restaurant,$meal]);
    $scalar($db,'SELECT COUNT(*) FROM ydy_recipes r JOIN ydy_dishes d'
        .' ON d.uuid=r.dishes_uuid WHERE r.menu_date=?'
        .' AND r.restaurant_id=? AND r.meal_times=? AND d.is_del=1'
        .' AND d.status=1 AND d.store_id=10001',
        [$date,$restaurant,$meal]);
    $scalar($db,'SELECT COUNT(DISTINCT menu_date) FROM ydy_recipes'
        .' WHERE restaurant_id=?',[$restaurant]);
    $menu=$db->prepare('SELECT uuid,filter FROM ydy_menu'
        .' WHERE LOWER(filter) LIKE ?');
    $menu->execute(['%p/bill/look_bill_list%']);
    $menu->fetchAll(PDO::FETCH_ASSOC);
    $timing['source_counts_menu_ms']=(int)round((microtime(true)-$t)*1000);

    $phase='old-connection-select1';
    $lastSelectAt=microtime(true);
    $old=['status'=>'unknown'];
    try {
        $prepareAt=microtime(true);
        $stmt=$db->prepare('SELECT 1');
        $stmt->execute();
        $old=[
            'status'=>(int)$stmt->fetchColumn()===1?'pass':'unexpected',
            'last_select_to_prepare_ms'=>(int)round(($prepareAt-$lastSelectAt)*1000),
            'prepare_execute_ms'=>(int)round((microtime(true)-$prepareAt)*1000),
        ];
    } catch (Throwable $error) {
        $old=['status'=>'fail','class'=>get_class($error),
            'code'=>(string)$error->getCode(),
            'last_select_to_prepare_ms'=>(int)round(($prepareAt-$lastSelectAt)*1000),
            'prepare_execute_ms'=>(int)round((microtime(true)-$prepareAt)*1000)];
    }
    $phase='fresh-connection-select1';
    $t=microtime(true);
    $fresh=$open();
    $stmt=$fresh->prepare('SELECT 1');
    $stmt->execute();
    $freshOkay=(int)$stmt->fetchColumn()===1;
    echo json_encode([
        'status'=>$freshOkay?'read-only-profile-complete':'fresh-connection-failed',
        'timing_ms'=>$timing,
        'old_connection'=>$old,
        'fresh_connection'=>[
            'status'=>$freshOkay?'pass':'fail',
            'connect_prepare_select_ms'=>(int)round((microtime(true)-$t)*1000),
        ],
        'business_http_sent'=>false,'database_write_count'=>0,
    ],JSON_UNESCAPED_SLASHES).PHP_EOL;
    if (!$freshOkay) exit(1);
} catch (Throwable $error) {
    echo json_encode(['status'=>'blocked','phase'=>$phase,
        'class'=>get_class($error),
        'code'=>(string)$error->getCode(),
        'timing_ms'=>$timing],JSON_UNESCAPED_SLASHES).PHP_EOL;
    exit(1);
}
