<?php

declare(strict_types=1);

// Isolated Department.transfer fixture. Default mode is SELECT-only and no HTTP/DML.
$lane = (string)getenv('CDX_TRANSFER_LANE');
$action = (string)($argv[1] ?? '');
$targets = [
    'A' => ['/tmp/zhct-http-store-a.l5omH8', 'http://127.0.0.1:18097', 21023,
        'mysql', '2a66074564ce33ddeae2a960cf3bd49128b5261b750dbca6a7d8b467a21d2540'],
    'B' => ['/tmp/zhct-http-store-mysql.dQTTBP', 'http://127.0.0.1:18081', 10001,
        'mysql', '665e4ba4639c1d27448524228ce3ad4568de1700a578d7dc17d98de197e54c5a'],
    'C' => ['/tmp/zhct-dm-poc-20260928.fcpiiN/store', 'http://127.0.0.1:18080', 112175,
        'dm', '665e4ba4639c1d27448524228ce3ad4568de1700a578d7dc17d98de197e54c5a'],
];
if (!isset($targets[$lane]) || !in_array($action, ['--preflight', '--execute'], true)
    || ($action === '--execute'
        && ((string)getenv('CDX_TRANSFER_EXECUTE') !== 'ROOT_APPROVED_TRANSFER_V1'
            || (string)getenv('CDX_TRANSFER_SHA') !== hash_file('sha256', __FILE__)))) {
    fwrite(STDERR, "Department transfer write/HTTP disabled\n");
    exit(78);
}
[$root, $base, $pid, $dialect, $logicSha] = $targets[$lane];
if ((string)getenv('POC_APP_ROOT') !== $root
    || (string)getenv('POC_BASE_URL') !== $base
    || (string)getenv('POC_DIALECT') !== $dialect
    || is_link($root)
    || hash_file('sha256', $root . '/application/p/controller/Department.php')
        !== ($lane === 'A'
            ? '4c7dc5220e5af83ef3f401bccd4577ab1daccec955de51cb0ce893dd005b9db0'
            : '80cf65100337d7a1458ef8533f4967b105ddbf5b97e6a66c205ede20ee97e484')
    || hash_file('sha256', $root . '/application/p/logic/Department.php') !== $logicSha
    || hash_file('sha256', $root . '/application/model/Department.php')
        !== ($lane === 'A'
            ? 'a0910fe7209b7da3e6a43a1697ea7a049bbd6e94d2c08225cdefe90f368efce8'
            : '9cd5a91f10f238d932d062e1fe8fae74208496b65d639314c545ecec49cc0e1f')
    || hash_file('sha256', $root . '/application/model/StaffDepartment.php')
        !== 'c450c5b72f6e5f1a9f0c0736922b1ccdc1f160b9637970857cf6b794d6becf29') {
    throw new RuntimeException('Approved transfer source/runtime drift');
}
$runtimeReady = static function () use ($root, $base, $pid): bool {
    $cmdline = (string)@file_get_contents('/proc/' . $pid . '/cmdline');
    $environment = (string)@file_get_contents('/proc/' . $pid . '/environ');
    $children = (string)@file_get_contents('/proc/' . $pid . '/task/' . $pid . '/children');
    $boundary = json_decode((string)@file_get_contents($base . '/__poc_boundary'), true);
    $port = (int)parse_url($base, PHP_URL_PORT);
    $hex = strtoupper(str_pad(dechex($port), 4, '0', STR_PAD_LEFT));
    $inode = '';
    foreach (@file('/proc/net/tcp', FILE_IGNORE_NEW_LINES) ?: [] as $line) {
        $parts = preg_split('/\s+/', trim($line));
        if (($parts[1] ?? '') === '0100007F:' . $hex && ($parts[3] ?? '') === '0A') {
            $inode = (string)($parts[9] ?? '');
            break;
        }
    }
    $ownsPort = false;
    if ($inode !== '') {
        foreach (@scandir('/proc/' . $pid . '/fd') ?: [] as $fd) {
            if ($fd !== '.' && $fd !== '..'
                && @readlink('/proc/' . $pid . '/fd/' . $fd)
                    === 'socket:[' . $inode . ']') {
                $ownsPort = true;
                break;
            }
        }
    }
    $multiWorker = preg_match('/(?:^|\x00)PHP_CLI_SERVER_WORKERS=(\d+)(?:\x00|$)/',
        $environment, $match) && (int)$match[1] > 1;
    return strpos($cmdline, '127.0.0.1:' . $port) !== false
        && strpos($cmdline, $root . '/public') !== false
        && $environment !== '' && trim($children) === '' && !$multiWorker
        && $ownsPort && is_array($boundary)
        && !empty($boundary['external_stubs'])
        && !empty($boundary['redis_isolated']) && empty($boundary['real_queue']);
};
if (!$runtimeReady()) throw new RuntimeException('Transfer isolated HTTP boundary absent');

$runtime = (static function (string $path): array {
    $config = require $path;
    if (!is_array($config)) throw new RuntimeException('Transfer runtime DB config invalid');
    return $config;
})($root . '/application/database.php');
if ((string)($runtime['prefix'] ?? '') !== 'ydy_') {
    throw new RuntimeException('Transfer table prefix mismatch');
}
if ($dialect === 'mysql') {
    $local = (static function (): array {
        $config = require '/workspace/zhct/zhctproject/store/application/config/local/database.php';
        if (!is_array($config)) throw new RuntimeException('Transfer local config invalid');
        return $config;
    })();
    if ((string)($runtime['type'] ?? '') !== 'mysql') {
        throw new RuntimeException('Not code local MySQL');
    }
    foreach (['hostname', 'database', 'username', 'password'] as $key) {
        if (($runtime[$key] ?? null) !== ($local[$key] ?? null)) {
            throw new RuntimeException('Transfer runtime differs from code local');
        }
    }
    if ((int)($runtime['hostport'] ?? 3306) !== (int)($local['hostport'] ?? 3306)) {
        throw new RuntimeException('Transfer local port mismatch');
    }
    $dsn = 'mysql:host=' . $runtime['hostname'] . ';port='
        . (int)($runtime['hostport'] ?? 3306) . ';dbname=' . $runtime['database']
        . ';charset=' . (string)($runtime['charset'] ?? 'utf8');
    $approvedDbSha = '003eb5aecf1cd4595b609c1f7f20b9ee325b578309fb9fe14fedaf77584fa401';
} else {
    if ((string)($runtime['type'] ?? '') !== 'app\\cores\\database\\Dm'
        || (string)getenv('POC_HOST') !== '127.0.0.1'
        || (string)getenv('POC_PORT') !== '5237'
        || strtoupper((string)getenv('POC_SCHEMA')) !== 'ZHCT_APP'
        || strtoupper((string)getenv('POC_USER')) !== 'ZHCT_APP') {
        throw new RuntimeException('Transfer DM target mismatch');
    }
    foreach (['hostname' => 'POC_HOST', 'hostport' => 'POC_PORT',
        'database' => 'POC_SCHEMA', 'username' => 'POC_USER',
        'password' => 'POC_PASSWORD'] as $key => $envKey) {
        if ((string)($runtime[$key] ?? '') !== (string)getenv($envKey)) {
            throw new RuntimeException('Transfer DM worker context mismatch');
        }
    }
    $machine = trim((string)@file_get_contents('/etc/machine-id'));
    if ($machine === '' || gethostname() === false
        || hash('sha256', gethostname() . '|' . $machine)
            !== 'd56d81988bb0f106946cce91c608fdd0ef1116e5150b23376ea87e086eace4b9') {
        throw new RuntimeException('Transfer DM host mismatch');
    }
    $lines = [];
    $code = 0;
    @exec('/usr/sbin/ss -ltnp 2>/dev/null', $lines, $code);
    $localListener = false;
    if ($code === 0) foreach ($lines as $line) {
        if (preg_match('/\*:5237\s+.*users:\(\("dmserver",pid=(\d+),/',
            $line, $match)) {
            $exe = @readlink('/proc/' . $match[1] . '/exe');
            $localListener = is_string($exe) && basename($exe) === 'dmserver';
            break;
        }
    }
    if (!$localListener) throw new RuntimeException('Transfer DM listener not local');
    $dsn = 'dm:host=127.0.0.1;port=5237;schema=ZHCT_APP';
    $approvedDbSha = 'bc98485aed26beab348770a82ae38dbf922b04ab88a210cd7282c4caf0156194';
}
$connect = static function () use ($runtime, $dialect, $dsn, $approvedDbSha): PDO {
    $pdo = new PDO($dsn, (string)$runtime['username'],
        (string)$runtime['password'], [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_CASE => PDO::CASE_LOWER, PDO::ATTR_TIMEOUT => 5]);
    $identity = $dialect === 'mysql'
        ? (string)$pdo->query(
            "SELECT CONCAT(@@server_uuid,'|',@@hostname,'|',@@port,'|',DATABASE())"
        )->fetchColumn()
        : 'ZHCT_APP|5237|' . (string)$pdo->query(
            "SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL"
        )->fetchColumn();
    if (!hash_equals($approvedDbSha, hash('sha256', $identity))) {
        throw new RuntimeException('Transfer DB identity outside approved target');
    }
    return $pdo;
};
$db = $connect();
$p = $dialect === 'dm' ? 'YDY_' : 'ydy_';
$requiredTables = ['department', 'staff', 'staff_department', 'user'];
$columnPresent = static function (string $table, string $column) use ($db, $dialect, $p): bool {
    if ($dialect === 'mysql') {
        $stmt = $db->prepare('SELECT COUNT(*) FROM information_schema.COLUMNS'
            . ' WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? AND COLUMN_NAME=?');
        $stmt->execute([$p . $table, $column]);
    } else {
        $stmt = $db->prepare('SELECT COUNT(*) FROM USER_TAB_COLUMNS'
            . ' WHERE TABLE_NAME=? AND COLUMN_NAME=?');
        $stmt->execute([$p . strtoupper($table), strtoupper($column)]);
    }
    return (int)$stmt->fetchColumn() === 1;
};
$required = [
    'department' => ['ID', 'UUID', 'NAME', 'CHARGE_BY', 'LEADER',
        'LEAF_FLAG', 'CREATE_TIME', 'CREATE_BY'],
    'staff' => ['ID', 'UUID', 'STATION_UUID', 'NAME', 'BIRTHDAY',
        'SPORT_UUID', 'SPORT_EVENT_UUID', 'CREATE_TIME', 'CREATE_BY',
        'PERSONNEL_UMBER', 'PERMANENT_ADDRESS', 'COACH_NAME', 'SPORT_YEAR'],
    'staff_department' => ['ID', 'DEPARTMENT_UUID', 'STAFF_UUID',
        'CREATE_TIME', 'CREATE_BY'],
    'user' => ['ID', 'UUID', 'ACCOUNT', 'PWD', 'SALT', 'NAME',
        'TYPE', 'CREATE_TIME', 'CREATE_BY'],
];
if ($dialect === 'mysql') $required['staff'][] = 'IN_TIME';
foreach ($required as $table => $fields) {
    foreach ($fields as $field) {
        if (!$columnPresent($table, $dialect === 'dm' ? $field : strtolower($field))) {
            throw new RuntimeException('Transfer fixture column absent');
        }
    }
}
$managedByDingtalk = $columnPresent('staff_department',
    $dialect === 'dm' ? 'MANAGED_BY_DINGTALK' : 'managed_by_dingtalk');
if ($managedByDingtalk !== ($dialect === 'mysql')) {
    throw new RuntimeException('Transfer audited optional column drift');
}
$idDefinitionShas = [];
foreach ($requiredTables as $table) {
    if ($dialect === 'mysql') {
        $stmt = $db->prepare('SELECT EXTRA FROM information_schema.COLUMNS'
            . ' WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? AND COLUMN_NAME=?');
        $stmt->execute([$p . $table, 'id']);
        $extra = (string)$stmt->fetchColumn();
        if (stripos($extra, 'auto_increment') === false) {
            throw new RuntimeException('Transfer MySQL fixture ID not auto increment');
        }
        $idDefinitionShas[$table] = hash('sha256', $extra);
    } else {
        $stmt = $db->prepare('CALL SP_TABLEDEF(?, ?)');
        $stmt->execute(['ZHCT_APP', $p . strtoupper($table)]);
        $definition = $stmt->fetchColumn();
        if (is_resource($definition)) $definition = stream_get_contents($definition);
        $definition = (string)$definition;
        if (!preg_match('/"ID"\s+BIGINT\s+AUTO_INCREMENT\s+NOT\s+NULL/i',
            $definition)) {
            throw new RuntimeException('Transfer DM fixture ID not auto increment');
        }
        $idDefinitionShas[$table] = hash('sha256', $definition);
    }
}
$uniquePairs = [];
if ($dialect === 'mysql') {
    $stmt = $db->prepare('SELECT INDEX_NAME,SEQ_IN_INDEX,COLUMN_NAME'
        . ' FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=DATABASE()'
        . ' AND TABLE_NAME=? AND NON_UNIQUE=0 ORDER BY INDEX_NAME,SEQ_IN_INDEX');
    $stmt->execute([$p . 'staff_department']);
    foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $raw) {
        $row = array_change_key_case($raw, CASE_LOWER);
        $uniquePairs[(string)$row['index_name']][] = strtolower((string)$row['column_name']);
    }
    $sqlMode = (string)$db->query('SELECT @@sql_mode')->fetchColumn();
    if (strpos($sqlMode, 'STRICT_') !== false) {
        throw new RuntimeException('Transfer MySQL strict mode changed');
    }
    $foreignKeys = (int)$db->query(
        "SELECT COUNT(*) FROM information_schema.KEY_COLUMN_USAGE"
        . " WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME IN"
        . " ('ydy_department','ydy_staff','ydy_staff_department')"
        . ' AND REFERENCED_TABLE_NAME IS NOT NULL')->fetchColumn();
    $incomingKeys = (int)$db->query(
        "SELECT COUNT(*) FROM information_schema.KEY_COLUMN_USAGE"
        . " WHERE REFERENCED_TABLE_SCHEMA=DATABASE() AND REFERENCED_TABLE_NAME IN"
        . " ('ydy_department','ydy_staff','ydy_staff_department')")->fetchColumn();
    $triggers = (int)$db->query(
        "SELECT COUNT(*) FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA=DATABASE()"
        . " AND EVENT_OBJECT_TABLE IN"
        . " ('ydy_department','ydy_staff','ydy_staff_department')")->fetchColumn();
} else {
    $rows = $db->query(
        "SELECT i.INDEX_NAME,c.COLUMN_NAME,c.COLUMN_POSITION"
        . ' FROM USER_INDEXES i JOIN USER_IND_COLUMNS c'
        . ' ON c.INDEX_NAME=i.INDEX_NAME AND c.TABLE_NAME=i.TABLE_NAME'
        . " WHERE i.TABLE_NAME='YDY_STAFF_DEPARTMENT' AND i.UNIQUENESS='UNIQUE'"
        . ' ORDER BY i.INDEX_NAME,c.COLUMN_POSITION')->fetchAll(PDO::FETCH_ASSOC);
    foreach ($rows as $raw) {
        $row = array_change_key_case($raw, CASE_LOWER);
        $uniquePairs[(string)$row['index_name']][] = strtolower((string)$row['column_name']);
    }
    $foreignKeys = (int)$db->query(
        "SELECT COUNT(*) FROM USER_CONSTRAINTS WHERE CONSTRAINT_TYPE='R'"
        . " AND TABLE_NAME IN ('YDY_DEPARTMENT','YDY_STAFF','YDY_STAFF_DEPARTMENT')"
    )->fetchColumn();
    $incomingKeys = (int)$db->query(
        "SELECT COUNT(*) FROM ALL_CONSTRAINTS c JOIN ALL_CONSTRAINTS parent"
        . ' ON c.R_OWNER=parent.OWNER AND c.R_CONSTRAINT_NAME=parent.CONSTRAINT_NAME'
        . " WHERE c.CONSTRAINT_TYPE='R' AND parent.OWNER='ZHCT_APP'"
        . " AND parent.TABLE_NAME IN"
        . " ('YDY_DEPARTMENT','YDY_STAFF','YDY_STAFF_DEPARTMENT')"
    )->fetchColumn();
    $triggers = (int)$db->query(
        "SELECT COUNT(*) FROM USER_TRIGGERS WHERE TABLE_NAME IN"
        . " ('YDY_DEPARTMENT','YDY_STAFF','YDY_STAFF_DEPARTMENT')"
    )->fetchColumn();
}
$hasCompositeUnique = false;
foreach ($uniquePairs as $fields) {
    if ($fields === ['department_uuid', 'staff_uuid']) {
        $hasCompositeUnique = true;
        break;
    }
}
if (!$hasCompositeUnique || $foreignKeys !== 0 || $incomingKeys !== 0
    || $triggers !== 0) {
    throw new RuntimeException('Transfer index/FK/trigger boundary changed');
}
$prefixCount = 0;
foreach ($requiredTables as $table) {
    $column = $table === 'staff_department' ? 'STAFF_UUID'
        : ($table === 'user' ? 'ACCOUNT' : 'UUID');
    $stmt = $db->prepare('SELECT COUNT(*) FROM ' . $p . $table
        . ' WHERE ' . $column . ' LIKE ?');
    $stmt->execute(['CDXDTR%']);
    $prefixCount += (int)$stmt->fetchColumn();
}
$marker = 'CDXDTR' . strtoupper(bin2hex(random_bytes(6)));
$staffUuid = $marker . 'S';
$sourceUuid = $marker . 'A';
$targetOneUuid = $marker . 'B';
$targetTwoUuid = $marker . 'C';
$ids = [$marker, $staffUuid, $sourceUuid, $targetOneUuid, $targetTwoUuid];
$exactCounts = [];
foreach (['department' => [$sourceUuid, $targetOneUuid, $targetTwoUuid],
    'staff' => [$staffUuid], 'user' => [$marker]] as $table => $keys) {
    $column = $table === 'user' ? 'ACCOUNT' : 'UUID';
    $stmt = $db->prepare('SELECT COUNT(*) FROM ' . $p . $table
        . ' WHERE ' . $column . ' IN (' . implode(',', array_fill(0, count($keys), '?')) . ')');
    $stmt->execute($keys);
    $exactCounts[$table] = (int)$stmt->fetchColumn();
}
$stmt = $db->prepare('SELECT COUNT(*) FROM ' . $p . 'staff_department'
    . ' WHERE STAFF_UUID=? OR DEPARTMENT_UUID IN (?,?,?)');
$stmt->execute([$staffUuid, $sourceUuid, $targetOneUuid, $targetTwoUuid]);
$exactCounts['staff_department'] = (int)$stmt->fetchColumn();
if ($prefixCount !== 0 || array_sum($exactCounts) !== 0) {
    throw new RuntimeException('Transfer synthetic marker collision or residue');
}
$preflight = ['lane' => $lane, 'dialect' => $dialect,
    'approved_database_identity' => true,
    'isolated_http_boundary' => true,
    'source_sha_gates_passed' => true,
    'required_fixture_columns_present' => true,
    'fixture_ids_auto_increment_confirmed' => true,
    'fixture_id_definition_shas' => $idDefinitionShas,
    'composite_unique_present' => true,
    'incoming_fk' => $incomingKeys,
    'outgoing_fk' => $foreignKeys,
    'table_triggers' => $triggers,
    'mysql_nonstrict' => $dialect === 'mysql' ? true : null,
    'mysql_only_managed_by_dingtalk' => $managedByDingtalk,
    'stale_synthetic_prefix_rows' => $prefixCount,
    'exact_new_marker_rows' => $exactCounts,
    'business_http_executed' => false,
    'dml_executed' => false];
if ($action === '--preflight') {
    echo json_encode($preflight, JSON_UNESCAPED_SLASHES), PHP_EOL;
    exit(0);
}
if ((string)getenv('CDX_TRANSFER_DB_SHA') !== $approvedDbSha) {
    throw new RuntimeException('Transfer execution DB fingerprint confirmation absent');
}

// A separate explicit user authorization and current script SHA are required
// before any fixture INSERT, the formal transfer HTTP, or cleanup DELETE.
$privateDir = sys_get_temp_dir() . '/zhct-transfer-' . $marker;
if (file_exists($privateDir) || !mkdir($privateDir, 0700)) {
    throw new RuntimeException('Transfer private journal directory unavailable');
}
chmod($privateDir, 0700);
$journalPath = $privateDir . '/recovery.json';
$journal = ['lane' => $lane, 'marker' => $marker,
    'staff_uuid' => $staffUuid,
    'department_uuids' => [$sourceUuid, $targetOneUuid, $targetTwoUuid],
    'actor_id' => 0, 'state' => 'prepared'];
$saveJournal = static function () use (&$journal, $privateDir, $journalPath): void {
    $next = $privateDir . '/recovery.next';
    if (file_put_contents($next, json_encode($journal, JSON_UNESCAPED_SLASHES)) === false) {
        throw new RuntimeException('Transfer recovery journal write failed');
    }
    chmod($next, 0600);
    if (!rename($next, $journalPath)) {
        throw new RuntimeException('Transfer recovery journal replace failed');
    }
};
$saveJournal();
$now = date('Y-m-d H:i:s');
$actorSalt = strtoupper(bin2hex(random_bytes(8)));
$actorId = 0;
$fixtureCommitted = false;
$response = [];
$beforeState = [];
$afterState = [];
$stateConsistent = false;
$positive = false;
$rollback = false;
$cleaned = false;
$privateCleared = false;
$failure = '';
$httpSent = false;
$httpConfirmedComplete = false;
$sourceLinkId = 0;
$oldTargetId = 0;
$readRows = static function (PDO $pdo, string $sql, array $args = []): array {
    $stmt = $pdo->prepare($sql);
    $stmt->execute($args);
    $rows = [];
    foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $raw) {
        $row = [];
        foreach (array_change_key_case($raw, CASE_LOWER) as $key => $value) {
            $row[$key] = is_resource($value) ? stream_get_contents($value) : $value;
        }
        $rows[] = $row;
    }
    return $rows;
};
$readState = static function (PDO $pdo) use ($p, $dialect, $staffUuid,
    $sourceUuid, $targetOneUuid, $targetTwoUuid, $readRows): array {
    $fields = 'ID,DEPARTMENT_UUID,STAFF_UUID,CREATE_TIME,CREATE_BY';
    if ($dialect === 'mysql') $fields .= ',MANAGED_BY_DINGTALK';
    $relations = $readRows($pdo,
        'SELECT ' . $fields . ' FROM ' . $p . 'staff_department'
            . ' WHERE STAFF_UUID=? AND DEPARTMENT_UUID IN (?,?,?)'
            . ' ORDER BY DEPARTMENT_UUID,ID',
        [$staffUuid, $sourceUuid, $targetOneUuid, $targetTwoUuid]);
    $departments = $readRows($pdo,
        'SELECT ID,UUID,LEAF_FLAG FROM ' . $p . 'department'
            . ' WHERE UUID IN (?,?,?) ORDER BY UUID,ID',
        [$sourceUuid, $targetOneUuid, $targetTwoUuid]);
    return ['relations' => $relations, 'departments' => $departments];
};
$getId = static function (PDO $pdo, string $table, string $uuid) use ($p): int {
    $stmt = $pdo->prepare('SELECT ID FROM ' . $p . $table . ' WHERE UUID=?');
    $stmt->execute([$uuid]);
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
    if (count($rows) !== 1) throw new RuntimeException('Transfer fixture ID ambiguous');
    return (int)(array_change_key_case($rows[0], CASE_LOWER)['id'] ?? 0);
};
$insertNamed = static function (PDO $pdo, string $table,
    array $fields) use ($p): void {
    $names = array_keys($fields);
    $stmt = $pdo->prepare('INSERT INTO ' . $p . $table . ' ('
        . implode(',', $names) . ') VALUES ('
        . implode(',', array_fill(0, count($fields), '?')) . ')');
    $stmt->execute(array_values($fields));
    if ($stmt->rowCount() !== 1) throw new RuntimeException('Transfer fixture insert failed');
};
$relationId = static function (PDO $pdo, string $departmentUuid,
    string $employeeUuid) use ($p): int {
    $stmt = $pdo->prepare('SELECT ID FROM ' . $p . 'staff_department'
        . ' WHERE DEPARTMENT_UUID=? AND STAFF_UUID=?');
    $stmt->execute([$departmentUuid, $employeeUuid]);
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
    if (count($rows) !== 1) throw new RuntimeException('Transfer relation ID ambiguous');
    return (int)(array_change_key_case($rows[0], CASE_LOWER)['id'] ?? 0);
};
try {
    // Setup is one fixture-only transaction, committed before HTTP worker reads it.
    $db->beginTransaction();
    try {
        $insertNamed($db, 'user', ['UUID' => $marker, 'ACCOUNT' => $marker,
            'PWD' => 'DISABLED', 'SALT' => $actorSalt,
            'NAME' => $marker, 'TYPE' => 0,
            'CREATE_TIME' => $now, 'CREATE_BY' => 'CODEX', 'IS_DELETE' => 0]);
        $actorId = $getId($db, 'user', $marker);
        $journal['actor_id'] = $actorId;
        $saveJournal();
        foreach ([[$sourceUuid, 1], [$targetOneUuid, 1], [$targetTwoUuid, 0]]
            as [$uuid, $leaf]) {
            $insertNamed($db, 'department', ['UUID' => $uuid,
                'PUUID' => '0', 'CODE' => $uuid, 'NAME' => $uuid,
                'CHARGE_BY' => $marker, 'LEADER' => $marker,
                'LEAF_FLAG' => $leaf, 'STATUS' => 1, 'IS_SHOW' => 1,
                'CREATE_TIME' => $now, 'CREATE_BY' => 'CODEX']);
            $journal['department_ids'][$uuid] = $getId($db, 'department', $uuid);
            $saveJournal();
        }
        $staff = ['UUID' => $staffUuid, 'STATION_UUID' => $marker . 'X',
            'NAME' => $marker, 'BIRTHDAY' => '2000-01-01',
            'SPORT_UUID' => $marker . 'Y', 'SPORT_EVENT_UUID' => '[]',
            'CREATE_TIME' => $now, 'CREATE_BY' => 'CODEX',
            'PERSONNEL_UMBER' => $marker, 'PERMANENT_ADDRESS' => $marker,
            'COACH_NAME' => $marker, 'SPORT_YEAR' => '0',
            'IS_SHOW' => 1, 'STATUS' => 1];
        if ($dialect === 'mysql') $staff['IN_TIME'] = '2020-01-01';
        $insertNamed($db, 'staff', $staff);
        $journal['staff_id'] = $getId($db, 'staff', $staffUuid);
        $saveJournal();
        $seedSource = ['DEPARTMENT_UUID' => $sourceUuid,
            'STAFF_UUID' => $staffUuid, 'CREATE_TIME' => '2001-01-02 03:04:05',
            'CREATE_BY' => 'CDXSEED'];
        $seedTarget = ['DEPARTMENT_UUID' => $targetOneUuid,
            'STAFF_UUID' => $staffUuid, 'CREATE_TIME' => '2001-01-03 03:04:05',
            'CREATE_BY' => 'CDXOLD'];
        if ($dialect === 'mysql') {
            $seedSource['MANAGED_BY_DINGTALK'] = 0;
            $seedTarget['MANAGED_BY_DINGTALK'] = 1;
        }
        $insertNamed($db, 'staff_department', $seedSource);
        $sourceLinkId = $relationId($db, $sourceUuid, $staffUuid);
        $journal['source_link_id'] = $sourceLinkId;
        $saveJournal();
        $insertNamed($db, 'staff_department', $seedTarget);
        $oldTargetId = $relationId($db, $targetOneUuid, $staffUuid);
        $journal['old_target_link_id'] = $oldTargetId;
        $saveJournal();
        $db->commit();
        $fixtureCommitted = true;
    } catch (Throwable $error) {
        if ($db->inTransaction()) $db->rollBack();
        throw $error;
    }
    $journal['state'] = 'fixture_committed';
    $saveJournal();
    $beforeState = $readState($connect());
    if (count($beforeState['relations']) !== 2
        || count($beforeState['departments']) !== 3) {
        throw new RuntimeException('Transfer fixture pre-HTTP state mismatch');
    }
    if (!$runtimeReady()) throw new RuntimeException('Transfer runtime drift before HTTP');
    require_once $root . '/application/base/Security.php';
    $token = \app\base\Security::encrypt(implode("\t",
        [(string)$actorId, $marker, $marker, '0', '', '', $marker]));
    if (!is_string($token) || $token === '') {
        throw new RuntimeException('Transfer synthetic token unavailable');
    }
    $context = stream_context_create(['http' => ['method' => 'POST',
        'header' => "Content-Type: application/x-www-form-urlencoded\r\n"
            . 'token: ' . $token . "\r\n",
        'content' => http_build_query(['uuid' => $sourceUuid,
            'department_uuid' => $targetOneUuid . ',' . $targetTwoUuid],
            '', '&', PHP_QUERY_RFC3986),
        'timeout' => 20, 'ignore_errors' => true]]);
    $stream = @fopen($base . '/p/department/transfer', 'rb', false, $context);
    $httpSent = true;
    $body = is_resource($stream) ? stream_get_contents($stream, 65537) : false;
    if (is_resource($stream)) fclose($stream);
    if (!is_string($body) || strlen($body) > 65536) {
        throw new RuntimeException('Transfer HTTP response unavailable or too large');
    }
    $httpConfirmedComplete = true;
    $headers = $http_response_header ?? [];
    preg_match('/HTTP\/\S+\s+(\d+)/', (string)($headers[0] ?? ''), $match);
    $json = json_decode($body, true);
    $response = ['http' => (int)($match[1] ?? 0),
        'code' => is_array($json) ? ($json['code'] ?? null) : null,
        'message_sha12' => substr(hash('sha256',
            is_array($json) ? (string)($json['message'] ?? '') : ''), 0, 12),
        'json_shape_valid' => is_array($json)];
    $afterState = $readState($connect());
    $relationsByDepartment = [];
    foreach ($afterState['relations'] as $row) {
        $relationsByDepartment[(string)$row['department_uuid']][] = $row;
    }
    $flags = [];
    foreach ($afterState['departments'] as $row) {
        $flags[(string)$row['uuid']] = (int)$row['leaf_flag'];
    }
    $targetOne = $relationsByDepartment[$targetOneUuid] ?? [];
    $targetTwo = $relationsByDepartment[$targetTwoUuid] ?? [];
    $positive = $response['http'] === 200 && $response['code'] === 0
        && count($afterState['departments']) === 3
        && empty($relationsByDepartment[$sourceUuid])
        && count($targetOne) === 1 && count($targetTwo) === 1
        && (int)$targetOne[0]['id'] !== $oldTargetId
        && (int)$targetTwo[0]['id'] > 0
        && ($flags[$sourceUuid] ?? null) === 0
        && ($flags[$targetOneUuid] ?? null) === 1
        && ($flags[$targetTwoUuid] ?? null) === 1;
    if ($positive && $dialect === 'mysql') {
        $positive = (int)($targetOne[0]['managed_by_dingtalk'] ?? -1) === 0
            && (int)($targetTwo[0]['managed_by_dingtalk'] ?? -1) === 0;
    }
    $rollback = ($response['http'] !== 200 || $response['code'] !== 0)
        && hash('sha256', serialize($afterState))
            === hash('sha256', serialize($beforeState));
    $stateConsistent = $positive || $rollback;
    if (!$stateConsistent) {
        throw new RuntimeException('Transfer partial success/rollback mismatch');
    }
} catch (Throwable $error) {
    $failure = get_class($error) . ':' . hash('sha256', $error->getMessage());
} finally {
    $workerStopped = !is_dir('/proc/' . $pid);
    $boundarySafe = ($workerStopped || !$httpSent || $httpConfirmedComplete)
        && ($workerStopped || $runtimeReady());
    if ($boundarySafe) {
        try {
            $cleanupDb = $connect();
            // Independent connection: prove every candidate row still belongs to
            // this exact marker before the first cleanup DELETE.
            $relationRows = $readRows($cleanupDb,
                'SELECT ID,DEPARTMENT_UUID,STAFF_UUID FROM ' . $p . 'staff_department'
                    . ' WHERE STAFF_UUID=? OR DEPARTMENT_UUID IN (?,?,?)'
                    . ' ORDER BY ID',
                [$staffUuid, $sourceUuid, $targetOneUuid, $targetTwoUuid]);
            if (count($relationRows) > 3) {
                throw new RuntimeException('Transfer extra synthetic relation needs review');
            }
            foreach ($relationRows as $row) {
                if ((string)$row['staff_uuid'] !== $staffUuid
                    || !in_array((string)$row['department_uuid'],
                        [$sourceUuid, $targetOneUuid, $targetTwoUuid], true)
                    || (int)$row['id'] <= 0) {
                    throw new RuntimeException('Transfer relation ownership drift');
                }
            }
            $departmentRows = $readRows($cleanupDb,
                'SELECT ID,UUID,NAME,CODE,PUUID,CHARGE_BY,LEADER,'
                    . 'STATUS,IS_SHOW,CREATE_BY FROM ' . $p . 'department'
                    . ' WHERE UUID IN (?,?,?) OR NAME IN (?,?,?) ORDER BY ID',
                [$sourceUuid, $targetOneUuid, $targetTwoUuid,
                    $sourceUuid, $targetOneUuid, $targetTwoUuid]);
            if (count($departmentRows) > 3) {
                throw new RuntimeException('Transfer extra department needs review');
            }
            foreach ($departmentRows as $row) {
                $uuid = (string)$row['uuid'];
                if (!in_array($uuid, [$sourceUuid, $targetOneUuid, $targetTwoUuid], true)
                    || (string)$row['name'] !== $uuid
                    || (string)$row['code'] !== $uuid
                    || (string)$row['puuid'] !== '0'
                    || (string)$row['charge_by'] !== $marker
                    || (string)$row['leader'] !== $marker
                    || (int)$row['status'] !== 1
                    || (int)$row['is_show'] !== 1
                    || (string)$row['create_by'] !== 'CODEX'
                    || (int)$row['id'] <= 0
                    || (isset($journal['department_ids'][$uuid])
                        && (int)$journal['department_ids'][$uuid] !== (int)$row['id'])) {
                    throw new RuntimeException('Transfer department ownership drift');
                }
            }
            $staffFields = 'ID,UUID,NAME,CREATE_BY,STATION_UUID,SPORT_UUID,'
                . 'SPORT_EVENT_UUID,BIRTHDAY,PERSONNEL_UMBER,PERMANENT_ADDRESS,'
                . 'COACH_NAME,SPORT_YEAR,STATUS,IS_SHOW';
            if ($dialect === 'mysql') $staffFields .= ',IN_TIME';
            $staffRows = $readRows($cleanupDb,
                'SELECT ' . $staffFields . ' FROM ' . $p . 'staff'
                    . ' WHERE UUID=? OR NAME=?', [$staffUuid, $marker]);
            if (count($staffRows) > 1) {
                throw new RuntimeException('Transfer extra staff needs review');
            }
            foreach ($staffRows as $row) {
                if ((string)$row['uuid'] !== $staffUuid
                    || (string)$row['name'] !== $marker
                    || (string)$row['create_by'] !== 'CODEX'
                    || (string)$row['station_uuid'] !== $marker . 'X'
                    || (string)$row['sport_uuid'] !== $marker . 'Y'
                    || (string)$row['sport_event_uuid'] !== '[]'
                    || substr((string)$row['birthday'], 0, 10) !== '2000-01-01'
                    || (string)$row['personnel_umber'] !== $marker
                    || (string)$row['permanent_address'] !== $marker
                    || (string)$row['coach_name'] !== $marker
                    || (string)$row['sport_year'] !== '0'
                    || (int)$row['status'] !== 1
                    || (int)$row['is_show'] !== 1
                    || ($dialect === 'mysql'
                        && substr((string)$row['in_time'], 0, 10) !== '2020-01-01')
                    || (int)$row['id'] <= 0
                    || (isset($journal['staff_id'])
                        && (int)$journal['staff_id'] !== (int)$row['id'])) {
                    throw new RuntimeException('Transfer staff ownership drift');
                }
            }
            $actorRows = $readRows($cleanupDb,
                'SELECT ID,UUID,ACCOUNT,NAME,PWD,SALT,TYPE,CREATE_BY FROM '
                    . $p . 'user'
                    . ' WHERE UUID=? OR ACCOUNT=?', [$marker, $marker]);
            if (count($actorRows) > 1) {
                throw new RuntimeException('Transfer extra actor needs review');
            }
            foreach ($actorRows as $row) {
                if ((string)$row['uuid'] !== $marker
                    || (string)$row['account'] !== $marker
                    || (string)$row['name'] !== $marker
                    || (string)$row['pwd'] !== 'DISABLED'
                    || (string)$row['salt'] !== $actorSalt
                    || (int)$row['type'] !== 0
                    || (string)$row['create_by'] !== 'CODEX'
                    || (int)$row['id'] <= 0
                    || ($actorId > 0 && (int)$row['id'] !== $actorId)) {
                    throw new RuntimeException('Transfer actor ownership drift');
                }
            }
            $cleanupDb->beginTransaction();
            try {
                $deleteRelation = $cleanupDb->prepare('DELETE FROM '
                    . $p . 'staff_department'
                    . ' WHERE ID=? AND STAFF_UUID=? AND DEPARTMENT_UUID=?');
                foreach ($relationRows as $row) {
                    $deleteRelation->execute([(int)$row['id'], $staffUuid,
                        (string)$row['department_uuid']]);
                    if ($deleteRelation->rowCount() !== 1) {
                        throw new RuntimeException('Transfer relation exact delete failed');
                    }
                }
                $deleteStaff = $cleanupDb->prepare('DELETE FROM ' . $p . 'staff'
                    . ' WHERE ID=? AND UUID=? AND NAME=? AND CREATE_BY=?');
                foreach ($staffRows as $row) {
                    $deleteStaff->execute([(int)$row['id'], $staffUuid,
                        $marker, 'CODEX']);
                    if ($deleteStaff->rowCount() !== 1) {
                        throw new RuntimeException('Transfer staff exact delete failed');
                    }
                }
                $deleteDept = $cleanupDb->prepare('DELETE FROM ' . $p . 'department'
                    . ' WHERE ID=? AND UUID=? AND NAME=? AND CREATE_BY=?');
                foreach ($departmentRows as $row) {
                    $deleteDept->execute([(int)$row['id'],
                        (string)$row['uuid'], (string)$row['name'], 'CODEX']);
                    if ($deleteDept->rowCount() !== 1) {
                        throw new RuntimeException('Transfer department exact delete failed');
                    }
                }
                $deleteActor = $cleanupDb->prepare('DELETE FROM ' . $p . 'user'
                    . ' WHERE ID=? AND UUID=? AND ACCOUNT=? AND TYPE=0 AND CREATE_BY=?');
                foreach ($actorRows as $row) {
                    $deleteActor->execute([(int)$row['id'], $marker, $marker, 'CODEX']);
                    if ($deleteActor->rowCount() !== 1) {
                        throw new RuntimeException('Transfer actor exact delete failed');
                    }
                }
                $left = 0;
                foreach ([
                    ['user', 'UUID=? OR ACCOUNT=?', [$marker, $marker]],
                    ['department', 'UUID IN (?,?,?) OR NAME IN (?,?,?)',
                        [$sourceUuid, $targetOneUuid, $targetTwoUuid,
                            $sourceUuid, $targetOneUuid, $targetTwoUuid]],
                    ['staff', 'UUID=? OR NAME=?', [$staffUuid, $marker]],
                    ['staff_department', 'STAFF_UUID=? OR DEPARTMENT_UUID IN (?,?,?)',
                        [$staffUuid, $sourceUuid, $targetOneUuid, $targetTwoUuid]],
                ] as $probe) {
                    [$table, $where, $args] = $probe;
                    $stmt = $cleanupDb->prepare('SELECT COUNT(*) FROM ' . $p . $table
                        . ' WHERE ' . $where);
                    $stmt->execute($args);
                    $left += (int)$stmt->fetchColumn();
                }
                if ($left !== 0) {
                    throw new RuntimeException('Transfer marker remains before cleanup commit');
                }
                $cleanupDb->commit();
            } catch (Throwable $error) {
                if ($cleanupDb->inTransaction()) $cleanupDb->rollBack();
                throw $error;
            }
            $verifyDb = $connect();
            $remaining = 0;
            foreach ([
                ['user', 'UUID=? OR ACCOUNT=?', [$marker, $marker]],
                ['department', 'UUID IN (?,?,?) OR NAME IN (?,?,?)',
                    [$sourceUuid, $targetOneUuid, $targetTwoUuid,
                        $sourceUuid, $targetOneUuid, $targetTwoUuid]],
                ['staff', 'UUID=? OR NAME=?', [$staffUuid, $marker]],
                ['staff_department', 'STAFF_UUID=? OR DEPARTMENT_UUID IN (?,?,?)',
                    [$staffUuid, $sourceUuid, $targetOneUuid, $targetTwoUuid]],
            ] as $probe) {
                [$table, $where, $args] = $probe;
                $stmt = $verifyDb->prepare('SELECT COUNT(*) FROM ' . $p . $table
                    . ' WHERE ' . $where);
                $stmt->execute($args);
                $remaining += (int)$stmt->fetchColumn();
            }
            $cleaned = $remaining === 0;
            if (!$cleaned) throw new RuntimeException('Transfer synthetic rows remain');
        } catch (Throwable $error) {
            $failure .= ($failure === '' ? '' : ';') . 'cleanup:'
                . get_class($error) . ':' . hash('sha256', $error->getMessage());
        }
    } else {
        $failure .= ($failure === '' ? '' : ';')
            . ($httpSent && !$httpConfirmedComplete && !$workerStopped
                ? 'cleanup:uncertain_http_outcome'
                : 'cleanup:runtime_boundary_drift');
    }
    if ($cleaned) {
        if (is_file($journalPath)) @unlink($journalPath);
        if (is_file($privateDir . '/recovery.next')) @unlink($privateDir . '/recovery.next');
        $privateCleared = @rmdir($privateDir);
    } else {
        $journal['state'] = 'requires_manual_recovery';
        try { $saveJournal(); } catch (Throwable $error) { /* preserve old journal */ }
    }
}
$targetOneAfter = [];
$targetTwoAfter = [];
foreach ($afterState['relations'] ?? [] as $row) {
    if ((string)($row['department_uuid'] ?? '') === $targetOneUuid) $targetOneAfter[] = $row;
    if ((string)($row['department_uuid'] ?? '') === $targetTwoUuid) $targetTwoAfter[] = $row;
}
$classifyCreator = static function ($value) use ($marker): string {
    if ($value === null) return 'null';
    if ((string)$value === '') return 'empty';
    if ((string)$value === $marker) return 'actor_name';
    return 'other';
};
$result = ['lane' => $lane, 'dialect' => $dialect,
    'synthetic_marker' => $marker,
    'fixture_committed' => $fixtureCommitted,
    'formal_http_sent' => $httpSent,
    'http_response_confirmed_complete' => $httpConfirmedComplete,
    'response' => $response,
    'state_consistent' => $stateConsistent,
    'positive_path' => $positive,
    'rollback_path' => $rollback,
    'source_link_id_preserved_on_failure' => $rollback,
    'target_old_id_replaced' => $positive && count($targetOneAfter) === 1
        ? (int)$targetOneAfter[0]['id'] !== $oldTargetId : null,
    'target_one_creator_class' => count($targetOneAfter) === 1
        ? $classifyCreator($targetOneAfter[0]['create_by'] ?? null) : null,
    'target_two_creator_class' => count($targetTwoAfter) === 1
        ? $classifyCreator($targetTwoAfter[0]['create_by'] ?? null) : null,
    'mysql_managed_default_reset' => $dialect === 'mysql' && $positive
        ? (int)($targetOneAfter[0]['managed_by_dingtalk'] ?? -1) === 0 : null,
    'fixture_exact_cleanup_zero' => $cleaned,
    'private_journal_removed' => $privateCleared,
    'private_recovery_pointer' => $cleaned ? null : $privateDir,
    'failure' => $failure];
echo json_encode($result, JSON_UNESCAPED_SLASHES), PHP_EOL;
if ($failure !== '' || !$fixtureCommitted || !$stateConsistent
    || !$cleaned || !$privateCleared) exit(1);
