<?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('/^CDXNSD[A-F0-9]{8}$/D', $marker)
    || ($phase === '--run' && getenv('CDX_NSD_RUN') !== 'ONE_OWNED_STATION_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);
};
$stationUuid = $uuid('station');
$nutrition1 = $uuid('nutrition1');
$nutrition2 = $uuid('nutrition2');
$nutritionUuids = [$nutrition1, $nutrition2];
$name1 = $marker . '_A';
$name2 = $marker . '_B';

$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, $marker, $stationUuid, $nutritionUuids): array {
    return [
        'station' => $fetch('SELECT id,uuid,code FROM ydy_nutrition_station WHERE uuid=? OR code=?',
            [$stationUuid, $marker]),
        'nutrition' => $fetch('SELECT id,uuid,name,synopsis,img_path FROM ydy_nutrition'
            . ' WHERE uuid IN (?,?) OR name IN (?,?)',
            [$nutritionUuids[0], $nutritionUuids[1], $marker . '_A', $marker . '_B']),
        'ext' => $fetch('SELECT id,station_uuid,nutrition_uuid,num FROM ydy_nutrition_station_ext'
            . ' WHERE station_uuid=? OR nutrition_uuid IN (?,?)',
            [$stationUuid, $nutritionUuids[0], $nutritionUuids[1]]),
    ];
};
$before = $own();
if ($phase === '--audit') {
    $counts = array_map('count', $before);
    echo json_encode(['lane' => $lane, 'phase' => 'audit', 'marker' => $marker,
        'owned_count' => $counts, 'business_http' => 0, 'business_dml' => 0]), PHP_EOL;
    exit(array_sum($counts) ? 2 : 0);
}
if (array_sum(array_map('count', $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 () use ($port, $marker): array {
    $ctx = stream_context_create(['http' => [
        'method' => 'POST', 'header' => "Content-Type: application/x-www-form-urlencoded\r\n",
        'content' => http_build_query(['device_code' => $marker], '', '&', PHP_QUERY_RFC3986),
        'ignore_errors' => true, 'timeout' => 25, 'follow_location' => 0,
    ]]);
    $handle = @fopen('http://127.0.0.1:' . $port . '/p/api/getNutritionByDevice',
        'rb', false, $ctx);
    if (!is_resource($handle)) throw new RuntimeException('Isolated Store HTTP unavailable');
    $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 prefix=' . substr($raw, 0, 80));
    return $body;
};

$result = [];
$error = null;
$now = date('Y-m-d H:i:s');
try {
    $insert('INSERT INTO ydy_nutrition_station (uuid,code,position,date,use_time) VALUES (?,?,?,?,?)',
        [$stationUuid, $marker, $marker, $now, '[]']);
    foreach ([[$nutrition1, $name1, '', 'cdx\\one.png'],
              [$nutrition2, $name2, $marker . '_SYN', 'cdx\\two.png']] as $item) {
        $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 (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
            [$item[0], $item[1], $item[2], $stationUuid, 2.5,
                'g', 1, '袋', '[]', $marker, $item[3], $now, $marker, 1, 1, 1]);
    }
    $insert('INSERT INTO ydy_nutrition_station_ext (station_uuid,nutrition_uuid,num) VALUES (?,?,?)',
        [$stationUuid, $nutrition1, 1]);
    $insert('INSERT INTO ydy_nutrition_station_ext (station_uuid,nutrition_uuid,num) VALUES (?,?,?)',
        [$stationUuid, $nutrition2, 22]);
    $source = $own();
    if (count($source['station']) !== 1 || count($source['nutrition']) !== 2
        || count($source['ext']) !== 2) throw new RuntimeException('Fixture original-table count differs');
    $body = $http();
    $code = $body['code'] ?? null;
    $result['http_code'] = $code;
    $result['http_message'] = substr((string)($body['message'] ?? ''), 0, 180);
    if ((int)$code !== 0) throw new RuntimeException('getNutritionByDevice returned nonzero code');
    $slots = $body['data'] ?? null;
    if (!is_array($slots) || (count($slots) !== 22 && count($slots) !== 46)) {
        throw new RuntimeException('Expected 22/46 slot response');
    }
    $sourceByNum = [];
    foreach ($source['ext'] as $row) $sourceByNum[(int)$row['num']] = (string)$row['nutrition_uuid'];
    $sourceNutrition = [];
    foreach ($source['nutrition'] as $row) $sourceNutrition[(string)$row['uuid']] = $row;
    $shape = [];
    $occupied = [];
    foreach ($slots as $i => $slot) {
        if (!is_array($slot) || (int)($slot['num'] ?? 0) !== $i + 1
            || (string)($slot['device_uuid'] ?? '') !== $stationUuid) {
            throw new RuntimeException('Slot order or station source differs');
        }
        $keys = array_keys($slot);
        sort($keys);
        if ($keys !== ['device_uuid', 'img_host', 'img_path', 'num', 'nutrition_name', 'nutrition_uuid']) {
            throw new RuntimeException('Slot field set differs');
        }
        $shape[] = array_map('gettype', $slot);
        $slotNo = $i + 1;
        if (isset($sourceByNum[$slotNo])) {
            $nUuid = $sourceByNum[$slotNo];
            $row = $sourceNutrition[$nUuid];
            $expectedName = trim((string)$row['synopsis']) === ''
                ? (string)$row['name'] : (string)$row['synopsis'];
            if ((string)$slot['nutrition_uuid'] !== $nUuid
                || (string)$slot['nutrition_name'] !== $expectedName
                || (string)$slot['img_path'] !== str_replace('\\', '/', (string)$row['img_path'])) {
                throw new RuntimeException('Occupied slot differs from original tables at ' . $slotNo);
            }
            $occupied[] = $slotNo;
        } elseif ((string)$slot['nutrition_uuid'] !== ''
            || (string)$slot['nutrition_name'] !== ''
            || (string)$slot['img_path'] !== '') {
            throw new RuntimeException('Empty slot contains unexpected source value');
        }
    }
    if ($occupied !== [1, 22]) throw new RuntimeException('Occupied slot coverage differs');
    $result += ['http_business_ok' => true, 'slot_count' => count($slots),
        'occupied_slots' => $occupied, 'source_row_counts' => array_map('count', $source),
        'slot_shape_hash' => hash('sha256', json_encode($shape, JSON_UNESCAPED_SLASHES)),
        'slot1_types' => array_map('gettype', $slots[0]),
        'slot2_types' => array_map('gettype', $slots[1]),
        'slot22_types' => array_map('gettype', $slots[21]),
        'business_http' => 1];
} catch (Throwable $caught) {
    $error = $caught;
} finally {
    // Delete only rows carrying this script's exact deterministic UUIDs; never truncate a shared table.
    $current = $own();
    foreach ($current['ext'] as $row) {
        if ((string)$row['station_uuid'] === $stationUuid
            && in_array((string)$row['nutrition_uuid'], $nutritionUuids, true)) {
            $query = $db->prepare('DELETE FROM ydy_nutrition_station_ext WHERE id=? AND station_uuid=? AND nutrition_uuid=?');
            $query->execute([$row['id'], $stationUuid, $row['nutrition_uuid']]);
        }
    }
    foreach ($current['nutrition'] as $row) {
        if (in_array((string)$row['uuid'], $nutritionUuids, true)
            && in_array((string)$row['name'], [$name1, $name2], true)) {
            $query = $db->prepare('DELETE FROM ydy_nutrition WHERE id=? AND uuid=? AND name=?');
            $query->execute([$row['id'], $row['uuid'], $row['name']]);
        }
    }
    foreach ($current['station'] as $row) {
        if ((string)$row['uuid'] === $stationUuid && (string)$row['code'] === $marker) {
            $query = $db->prepare('DELETE FROM ydy_nutrition_station WHERE id=? AND uuid=? AND code=?');
            $query->execute([$row['id'], $stationUuid, $marker]);
        }
    }
    $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);
