<?php
declare(strict_types=1);

$phase = (string)($argv[1] ?? '');
$lane = (string)($argv[2] ?? '');
$marker = (string)($argv[3] ?? '');
if (!in_array($phase, ['--run', '--audit'], true) || !in_array($lane, ['B', 'C'], true)
    || !preg_match('/^CDXNSP[A-F0-9]{8}$/D', $marker)
    || ($phase === '--run' && getenv('CDX_NSP_RUN') !== 'ONE_OWNED_PLAN_V1')) {
    fwrite(STDERR, "DENIED business_http=0 business_dml=0\n"); exit(78);
}
if ($lane === 'B') {
    $config = include '/tmp/zhct-http-store-mysql.dQTTBP/application/config/local/database.php';
    if (!is_array($config) || ($config['database'] ?? '') !== 'zhct'
        || hash('sha256', (string)($config['hostname'] ?? ''))
            !== '47e8be48b0cfd56dcdb9d9d426e6637b245f340b4efad4cd2f084ec5851ecc8e') {
        throw new RuntimeException('B code-local MySQL identity drift');
    }
    $db = new PDO('mysql:host=' . $config['hostname'] . ';port=3306;dbname=zhct;charset=utf8',
        $config['username'], $config['password'],
        [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_CASE => PDO::CASE_LOWER]);
    $port = 18081;
} else {
    if (getenv('POC_DIALECT') !== 'dm' || getenv('POC_HOST') !== '127.0.0.1'
        || getenv('POC_PORT') !== '5237' || getenv('POC_SCHEMA') !== 'ZHCT_APP'
        || getenv('POC_USER') !== 'ZHCT_APP') {
        throw new RuntimeException('C isolated DM identity drift');
    }
    $db = new PDO('dm:host=127.0.0.1;port=5237;schema=ZHCT_APP',
        getenv('POC_USER'), getenv('POC_PASSWORD'),
        [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_CASE => PDO::CASE_LOWER]);
    if ($db->query("SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL")->fetchColumn() !== 'ZHCT_APP') {
        throw new RuntimeException('C schema drift');
    }
    $port = 18080;
}
$uuid = static function (string $suffix) use ($marker): string {
    $hex = substr(hash('sha256', $marker . ':' . $suffix), 0, 32);
    return substr($hex, 0, 8) . '-' . substr($hex, 8, 4) . '-4'
        . substr($hex, 13, 3) . '-a' . substr($hex, 17, 3) . '-' . substr($hex, 20, 12);
};
$ids = [
    'station' => $uuid('station'), 'nutrition' => $uuid('nutrition'),
    'time' => $uuid('time'), 'scheme' => $uuid('scheme'),
    'staff' => $uuid('staff'), 'staff_link' => $uuid('staff_link'),
    'scheme_ext' => $uuid('scheme_ext'),
];
$fetch = static function (string $sql, array $params = []) use ($db): array {
    $query = $db->prepare($sql);
    $query->execute($params);
    return array_map(static function (array $row): array {
        return array_change_key_case($row, CASE_LOWER);
    }, $query->fetchAll(PDO::FETCH_ASSOC));
};
$own = static function () use ($fetch, $ids, $marker): array {
    return [
        'station' => $fetch('SELECT id,uuid,code,use_time FROM ydy_nutrition_station WHERE uuid=? OR code=?',
            [$ids['station'], $marker]),
        'nutrition' => $fetch('SELECT id,uuid,name,synopsis,img_path,use_number_unit FROM ydy_nutrition WHERE uuid=? OR name=?',
            [$ids['nutrition'], $marker]),
        'station_ext' => $fetch('SELECT id,station_uuid,nutrition_uuid,num FROM ydy_nutrition_station_ext'
            . ' WHERE station_uuid=? OR nutrition_uuid=?', [$ids['station'], $ids['nutrition']]),
        'time' => $fetch('SELECT id,uuid,name FROM ydy_nutrition_time WHERE uuid=? OR name=?',
            [$ids['time'], $marker]),
        'scheme' => $fetch('SELECT id,uuid,name,start_time,end_time FROM ydy_nutrition_scheme WHERE uuid=? OR name=?',
            [$ids['scheme'], $marker]),
        'staff_link' => $fetch('SELECT id,uuid,staff_uuid,nutrition_scheme_uuid FROM ydy_nutrition_staff'
            . ' WHERE uuid=? OR staff_uuid=? OR nutrition_scheme_uuid=?',
            [$ids['staff_link'], $ids['staff'], $ids['scheme']]),
        'scheme_ext' => $fetch('SELECT id,uuid,nutrition_scheme_uuid,nutrition_uuid,use_time,type,use_volume,use_method'
            . ' FROM ydy_nutrition_scheme_ext WHERE uuid=? OR nutrition_scheme_uuid=? OR nutrition_uuid=?',
            [$ids['scheme_ext'], $ids['scheme'], $ids['nutrition']]),
        'cupboard' => $fetch('SELECT id,station_uuid,nutrition_uuid,current_num,all_num'
            . ' FROM ydy_nutrition_cupboard WHERE station_uuid=? OR nutrition_uuid=?',
            [$ids['station'], $ids['nutrition']]),
    ];
};
$before = array_map('count', $own());
if ($phase === '--audit') {
    echo json_encode(['lane' => $lane, 'phase' => 'audit', 'marker' => $marker,
        'owned_count' => $before, 'business_http' => 0, 'business_dml' => 0]), PHP_EOL;
    exit(array_sum($before) ? 2 : 0);
}
if (array_sum($before) !== 0) throw new RuntimeException('Owned fixture marker already exists');
$insert = static function (string $sql, array $params) use ($db): void {
    $query = $db->prepare($sql);
    $query->execute($params);
    if ($query->rowCount() !== 1) throw new RuntimeException('Fixture insert row count not one');
};
$http = static function (string $action, array $form) use ($port): array {
    if (!in_array($action, ['getTrainTime', 'getNutritionScheme'], true))
        throw new RuntimeException('Unsupported test endpoint');
    $ctx = stream_context_create(['http' => [
        'method' => 'POST', 'header' => "Content-Type: application/x-www-form-urlencoded\r\n",
        'content' => http_build_query($form, '', '&', PHP_QUERY_RFC3986),
        'ignore_errors' => true, 'timeout' => 25, 'follow_location' => 0,
    ]]);
    $handle = @fopen('http://127.0.0.1:' . $port . '/p/api/' . $action,
        'rb', false, $ctx);
    if (!is_resource($handle)) throw new RuntimeException('Isolated Store HTTP unavailable: ' . $action);
    $raw = stream_get_contents($handle, 262145);
    fclose($handle);
    if (!is_string($raw) || strlen($raw) > 262144) throw new RuntimeException('HTTP response cap');
    $body = json_decode($raw, true);
    if (!is_array($body)) throw new RuntimeException('Non-JSON HTTP response ' . $action . ' prefix=' . substr($raw, 0, 80));
    return $body;
};

$result = ['business_http' => 0];
$error = null;
$now = date('Y-m-d H:i:s');
$today = date('Y-m-d');
try {
    $insert('INSERT INTO ydy_nutrition_station (uuid,code,position,date,use_time) VALUES (?,?,?,?,?)',
        [$ids['station'], $marker, $marker, $now, $ids['time']]);
    $insert('INSERT INTO ydy_nutrition (uuid,name,synopsis,set_uuid,use_weight,'
        . 'use_weight_unit,use_number,use_number_unit,use_time,use_method,img_path,'
        . 'create_time,create_by,status,is_del,is_nutrition_station)'
        . ' VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
        [$ids['nutrition'], $marker, $marker . '_SYN', $ids['station'], 2.5,
            'g', 1, '1', $ids['time'], $marker . '_METHOD', 'cdx\\plan.png',
            $now, $marker, 1, 1, 1]);
    $insert('INSERT INTO ydy_nutrition_station_ext (station_uuid,nutrition_uuid,num) VALUES (?,?,?)',
        [$ids['station'], $ids['nutrition'], 1]);
    $insert('INSERT INTO ydy_nutrition_time (uuid,name,create_time,create_by) VALUES (?,?,?,?)',
        [$ids['time'], $marker, $now, $marker]);
    $insert('INSERT INTO ydy_nutrition_scheme'
        . ' (uuid,name,create_time,create_by,start_time,end_time) VALUES (?,?,?,?,?,?)',
        [$ids['scheme'], $marker, $now, $marker,
            date('Y-m-d', strtotime($today . ' -1 day')),
            date('Y-m-d', strtotime($today . ' +1 day'))]);
    $insert('INSERT INTO ydy_nutrition_staff'
        . ' (uuid,nutrition_scheme_uuid,staff_uuid,create_time,create_by) VALUES (?,?,?,?,?)',
        [$ids['staff_link'], $ids['scheme'], $ids['staff'], $now, $marker]);
    $insert('INSERT INTO ydy_nutrition_scheme_ext'
        . ' (uuid,nutrition_scheme_uuid,train_time,nutrition_uuid,use_volume,use_method,use_time,type,create_time,create_by)'
        . ' VALUES (?,?,?,?,?,?,?,?,?,?)',
        [$ids['scheme_ext'], $ids['scheme'], 1, $ids['nutrition'], '2.5',
            $marker . '_METHOD', $ids['time'], 1, $now, $marker]);
    $insert('INSERT INTO ydy_nutrition_cupboard'
        . ' (station_uuid,nutrition_uuid,current_num,all_num) VALUES (?,?,?,?)',
        [$ids['station'], $ids['nutrition'], 1, '1']);
    $sourceRows = $own();
    $source = array_map('count', $sourceRows);
    foreach ($source as $table => $count) {
        if ($count !== 1) throw new RuntimeException('Owned source count not one: ' . $table);
    }
    $station = $sourceRows['station'][0];
    $nutrition = $sourceRows['nutrition'][0];
    $time = $sourceRows['time'][0];
    $schemeRow = $sourceRows['scheme'][0];
    $staffLink = $sourceRows['staff_link'][0];
    $stationExt = $sourceRows['station_ext'][0];
    $schemeExt = $sourceRows['scheme_ext'][0];
    $cupboard = $sourceRows['cupboard'][0];
    if ((string)$station['code'] !== $marker
        || (string)$station['use_time'] !== $ids['time']
        || (string)$nutrition['uuid'] !== $ids['nutrition']
        || (string)$time['uuid'] !== $ids['time']
        || (string)$staffLink['staff_uuid'] !== $ids['staff']
        || (string)$staffLink['nutrition_scheme_uuid'] !== $ids['scheme']
        || substr((string)$schemeRow['start_time'], 0, 10) > $today
        || substr((string)$schemeRow['end_time'], 0, 10) < $today
        || (string)$stationExt['station_uuid'] !== $ids['station']
        || (string)$stationExt['nutrition_uuid'] !== $ids['nutrition']
        || (int)$stationExt['num'] !== 1
        || (string)$schemeExt['nutrition_scheme_uuid'] !== $ids['scheme']
        || (string)$schemeExt['nutrition_uuid'] !== $ids['nutrition']
        || (string)$schemeExt['use_time'] !== $ids['time']
        || (int)$schemeExt['type'] !== 1
        || (string)$cupboard['station_uuid'] !== $ids['station']
        || (string)$cupboard['nutrition_uuid'] !== $ids['nutrition']
        || (int)$cupboard['current_num'] !== 1
        || (string)$cupboard['all_num'] !== '1') {
        throw new RuntimeException('Owned original-table relation mismatch');
    }
    $train = $http('getTrainTime', ['staff_uuid' => $ids['staff'], 'device_code' => $marker]);
    $result['business_http']++;
    $result['train_code'] = $train['code'] ?? null;
    $result['train_message'] = substr((string)($train['message'] ?? ''), 0, 160);
    if ((int)$result['train_code'] !== 0 || !isset($train['data'][0])
        || count($train['data']) !== 1
        || (string)($train['data'][0]['use_time'] ?? '') !== (string)$time['uuid']
        || (string)($train['data'][0]['name'] ?? '') !== (string)$time['name']) {
        throw new RuntimeException('getTrainTime differs from own source rows');
    }
    $result['train_types'] = array_map('gettype', $train['data'][0]);
    $scheme = $http('getNutritionScheme', [
        'staff_uuid' => $ids['staff'], 'device_code' => $marker, 'use_time' => $ids['time']]);
    $result['business_http']++;
    $result['scheme_code'] = $scheme['code'] ?? null;
    $result['scheme_message'] = substr((string)($scheme['message'] ?? ''), 0, 180);
    if ((int)$result['scheme_code'] !== 0 || !isset($scheme['data'][0])
        || count($scheme['data']) !== 1) {
        throw new RuntimeException('getNutritionScheme failed or did not return one own item');
    }
    $row = $scheme['data'][0];
    $unitLabels = ['1' => '袋', '2' => '片', '3' => '粒', '4' => '个', '5' => '根',
        '6' => '勺', '7' => '瓶', '8' => '盒', '9' => '份'];
    $expectedName = trim((string)$nutrition['synopsis']) === ''
        ? (string)$nutrition['name'] : (string)$nutrition['synopsis'];
    if ((int)($row['num'] ?? 0) !== (int)$stationExt['num']
        || (string)($row['nutrition_uuid'] ?? '') !== (string)$nutrition['uuid']
        || (string)($row['nutrition_name'] ?? '') !== $expectedName
        || (string)($row['use_volume'] ?? '') !== (string)$schemeExt['use_volume']
        || (string)($row['use_method'] ?? '') !== (string)$schemeExt['use_method']
        || (string)($row['img_path'] ?? '') !== str_replace('\\', '/', (string)$nutrition['img_path'])
        || (string)($row['nutrition_unit'] ?? '') !== ($unitLabels[(string)$nutrition['use_number_unit']] ?? '')
        || (string)($row['arr_key'] ?? '') !== (string)$nutrition['uuid'] . '-1') {
        throw new RuntimeException('getNutritionScheme fields differ from own source rows');
    }
    $result += ['http_business_ok' => true, 'source_counts' => $source,
        'scheme_types' => array_map('gettype', $row)];
} catch (Throwable $caught) {
    $error = $caught;
} finally {
    $current = $own();
    $rules = [
        'cupboard' => ['ydy_nutrition_cupboard', 'station_uuid', $ids['station']],
        'scheme_ext' => ['ydy_nutrition_scheme_ext', 'uuid', $ids['scheme_ext']],
        'staff_link' => ['ydy_nutrition_staff', 'uuid', $ids['staff_link']],
        'station_ext' => ['ydy_nutrition_station_ext', 'station_uuid', $ids['station']],
        'scheme' => ['ydy_nutrition_scheme', 'uuid', $ids['scheme']],
        'time' => ['ydy_nutrition_time', 'uuid', $ids['time']],
        'nutrition' => ['ydy_nutrition', 'uuid', $ids['nutrition']],
        'station' => ['ydy_nutrition_station', 'uuid', $ids['station']],
    ];
    foreach ($rules as $key => $rule) {
        foreach ($current[$key] as $row) {
            if ((string)$row[$rule[1]] !== $rule[2]) continue;
            $query = $db->prepare('DELETE FROM ' . $rule[0] . ' WHERE id=? AND ' . $rule[1] . '=?');
            $query->execute([$row['id'], $rule[2]]);
        }
    }
    $after = array_map('count', $own());
    $result['owned_after_cleanup'] = $after;
    if (array_sum($after) !== 0) $error = new RuntimeException('Owned cleanup not zero');
}
echo json_encode(['lane' => $lane, 'phase' => 'run', 'marker' => $marker,
    'result' => $result, 'error' => $error ? substr($error->getMessage(), 0, 240) : null],
    JSON_UNESCAPED_SLASHES), PHP_EOL;
exit($error ? 1 : 0);
