<?php

declare(strict_types=1);

$root = (string)getenv('POC_APP_ROOT');
$base = rtrim((string)getenv('POC_BASE_URL'), '/');
$dialect = (string)getenv('POC_DIALECT');
if (strpos($root, '/tmp/zhct-') !== 0 || $base === ''
    || !in_array($dialect, ['mysql', 'dm'], true)
    || !is_file($root . '/application/base/Security.php')
    || !is_file($root . '/vendor/autoload.php')) {
    throw new RuntimeException('Private health export runtime unavailable');
}
$boundaryContext = stream_context_create(['http' => ['timeout' => 5]]);
$boundaryRaw = @file_get_contents($base . '/__poc_boundary', false, $boundaryContext);
$boundary = is_string($boundaryRaw) ? json_decode($boundaryRaw, true) : null;
if (!is_array($boundary) || empty($boundary['external_stubs'])
    || empty($boundary['redis_isolated'])) {
    throw new RuntimeException('Health export isolation boundary missing');
}

$connect = static function (bool $ai) use ($dialect, $root): PDO {
    $prefix = $ai ? 'POC_AI_' : 'POC_';
    $values = [];
    foreach (['HOST', 'PORT', 'SCHEMA', 'USER', 'PASSWORD'] as $name) {
        $values[$name] = (string)getenv($prefix . $name);
    }
    $pid = (string)getenv('POC_RUNTIME_PID');
    if ($dialect === 'dm' && $values['HOST'] === '' && ctype_digit($pid)) {
        foreach (explode("\0", (string)file_get_contents('/proc/' . $pid . '/environ')) as $entry) {
            $parts = explode('=', $entry, 2);
            if (count($parts) === 2 && strpos($parts[0], $prefix) === 0) {
                $name = substr($parts[0], strlen($prefix));
                if (array_key_exists($name, $values)) $values[$name] = $parts[1];
            }
        }
    }
    if ($dialect === 'mysql' && $values['HOST'] === '') {
        $local = $root . '/application/config/local/database.php';
        $file = is_file($local) ? $local : $root . '/application/database.php';
        $config = (static function (string $path): array { return require $path; })($file);
        $selected = $ai ? $config['ai_zhct'] : $config;
        $values = ['HOST' => (string)($selected['hostname'] ?? $config['hostname']),
            'PORT' => (string)($selected['hostport'] ?? $config['hostport'] ?? 3306),
            'SCHEMA' => (string)$selected['database'],
            'USER' => (string)($selected['username'] ?? $config['username']),
            'PASSWORD' => (string)($selected['password'] ?? $config['password'])];
    }
    if ($values['HOST'] === '' || $values['SCHEMA'] === '' || $values['USER'] === '') {
        throw new RuntimeException('Health export DB configuration missing');
    }
    $dsn = $dialect === 'dm'
        ? "dm:host={$values['HOST']};port={$values['PORT']};schema={$values['SCHEMA']}"
        : "mysql:host={$values['HOST']};port={$values['PORT']};dbname={$values['SCHEMA']};charset=utf8mb4";
    return new PDO($dsn, $values['USER'], $values['PASSWORD'],
        [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_CASE => PDO::CASE_LOWER]);
};
$store = $connect(false);
$ai = $connect(true);
$table = static function (string $name, bool $isAi = false) use ($dialect): string {
    $prefix = $isAi ? 'yoshop_' : 'ydy_';
    return $dialect === 'dm' ? strtoupper($prefix . $name) : $prefix . $name;
};
$metric = $store->prepare('SELECT METRIC_NAME FROM ' . $table('health_metric')
    . ' WHERE METRIC_CODE=?');
$metric->execute(['weight']);
$metricName = (string)$metric->fetchColumn();
if ($metricName === '') throw new RuntimeException('Weight metric dictionary unavailable');

require_once $root . '/application/base/Security.php';
require_once $root . '/vendor/autoload.php';
$marker = 'CDXPARHEX' . strtoupper(bin2hex(random_bytes(6)));
$token = \app\base\Security::encrypt(implode("\t", ['0', $marker, $marker, '0', '', '', $marker]));
$userId = 0;
$sessions = [];
$tempFiles = [];
$day1 = '2001-01-02';
$day2 = '2001-01-03';
$time1 = $day1 . ' 10:00:00';
$time2 = $day2 . ' 10:00:00';
$results = [];
$send = static function (string $route, string $method, array $params,
    bool $auth = true) use ($base, $token): array {
    $encoded = http_build_query($params, '', '&', PHP_QUERY_RFC3986);
    $url = $base . $route . ($method === 'GET' ? '?' . $encoded : '');
    $headers = ($auth ? 'token: ' . $token . "\r\n" : '')
        . ($method === 'POST' ? "Content-Type: application/x-www-form-urlencoded\r\n" : '');
    $context = stream_context_create(['http' => [
        'method' => $method, 'header' => $headers,
        'content' => $method === 'POST' ? $encoded : '',
        'timeout' => 25, 'ignore_errors' => true,
    ]]);
    $body = file_get_contents($url, false, $context);
    $headerLines = $http_response_header ?? [];
    $status = (string)($headerLines[0] ?? '');
    if (strpos($status, ' 200 ') === false || !is_string($body)) {
        throw new RuntimeException('Health export HTTP transport failed');
    }
    $contentType = $disposition = '';
    foreach ($headerLines as $line) {
        if (stripos($line, 'Content-Type:') === 0) $contentType = $line;
        if (stripos($line, 'Content-Disposition:') === 0) $disposition = $line;
    }
    return ['body' => $body, 'content_type' => $contentType,
        'disposition' => $disposition];
};
$parseExcel = static function (array $response) use ($root, $marker, &$tempFiles): array {
    if (stripos($response['content_type'], 'application/vnd.ms-excel') === false
        || strpos($response['disposition'], $marker) === false
        || substr($response['body'], 0, 8) !== "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1") {
        throw new RuntimeException('Expected Excel5 binary download contract not returned');
    }
    $privateDir = $root . '/runtime';
    if (!is_dir($privateDir) || is_link($privateDir)
        || realpath($privateDir) !== $privateDir) {
        throw new RuntimeException('Private runtime output directory unavailable');
    }
    $file = tempnam($privateDir, 'CDXPARHEX');
    if ($file === false || strpos($file, $privateDir . '/') !== 0) {
        throw new RuntimeException('Could not create private Excel verification file');
    }
    $tempFiles[] = $file;
    file_put_contents($file, $response['body']);
    $reader = \PHPExcel_IOFactory::createReader('Excel5');
    $workbook = $reader->load($file);
    $rows = $workbook->getActiveSheet()->toArray(null, true, true, true);
    $workbook->disconnectWorksheets();
    return ['rows' => $rows, 'bytes' => strlen($response['body'])];
};
try {
    $insertUser = $ai->prepare('INSERT INTO ' . $table('user', true)
        . ' (STORE_ID,MOBILE,NICK_NAME,BALANCE,GIFT_BALANCE,IS_DELETE,CREATE_TIME)'
        . ' VALUES (10001,?,?,?,?,0,?)');
    $insertUser->execute(['', $marker, '0.00', '0.00', time()]);
    $findUser = $ai->prepare('SELECT USER_ID FROM ' . $table('user', true)
        . ' WHERE STORE_ID=10001 AND NICK_NAME=?');
    $findUser->execute([$marker]);
    $userId = (int)$findUser->fetchColumn();
    if ($userId <= 0) throw new RuntimeException('Synthetic health user not inserted');
    foreach ([[$time1, '70.50'], [$time2, '69.50']] as $row) {
        [$measuredAt, $weight] = $row;
        $insertSession = $store->prepare('INSERT INTO ' . $table('measurement_session')
            . ' (AI_USER_ID,EVENT_TYPE,START_TIME,SOURCE_PLATFORM,VENDOR,DEVICE_TYPE,'
            . ' DEVICE_MODEL,BUSINESS_CONTEXT,IS_VALID) VALUES (?,?,?,?,?,?,?,?,1)');
        $insertSession->execute([$userId, 'measurement', $measuredAt,
            'direct_device', 'zhaiker', 'body_scale', $marker, 'health']);
        $findSession = $store->prepare('SELECT SESSION_ID FROM ' . $table('measurement_session')
            . ' WHERE AI_USER_ID=? AND DEVICE_MODEL=? AND START_TIME=?');
        $findSession->execute([$userId, $marker, $measuredAt]);
        $sessionId = (int)$findSession->fetchColumn();
        if ($sessionId <= 0) throw new RuntimeException('Synthetic session not inserted');
        $sessions[] = $sessionId;
        $insertRecord = $store->prepare('INSERT INTO ' . $table('health_record')
            . ' (SESSION_ID,AI_USER_ID,METRIC_CODE,VALUE,UNIT,SEGMENT,SEGMENT_KEY,START_TIME)'
            . ' VALUES (?,?,?,?,?,NULL,?,?)');
        $insertRecord->execute([$sessionId, $userId, 'weight', $weight, 'kg', '', $measuredAt]);
    }
    $sourceQuery = $store->prepare('SELECT VALUE,START_TIME FROM ' . $table('health_record')
        . ' WHERE AI_USER_ID=? AND METRIC_CODE=? ORDER BY START_TIME');
    $sourceQuery->execute([$userId, 'weight']);
    $source = $sourceQuery->fetchAll(PDO::FETCH_ASSOC);
    if (count($source) !== 2
        || bccomp((string)$source[0]['value'], '70.50', 2) !== 0
        || bccomp((string)$source[1]['value'], '69.50', 2) !== 0) {
        throw new RuntimeException('Health report source readback not exact');
    }
    $trend = ['ai_user_id' => $userId, 'metric_codes' => 'weight',
        'start_date' => $day1, 'end_date' => $day2, 'file_name' => $marker];
    $rate = ['ai_user_id' => $userId,
        'metric_items' => json_encode([['metric_code' => 'weight', 'target_date' => $day2]]),
        'file_name' => $marker];
    foreach (['personalTrendExport' => $trend, 'personalChangeRateExport' => $rate] as $route => $params) {
        $unauth = $send('/p/zhaikerHealth/' . $route, 'GET', $params, false);
        $reject = json_decode($unauth['body'], true);
        $results[$route]['unauth'] = ['status' => is_array($reject)
            && (int)($reject['code'] ?? -1) === 100 ? 'tested-pass' : 'tested-fail'];
        foreach (['GET', 'POST'] as $method) {
            $response = $send('/p/zhaikerHealth/' . $route, $method, $params);
            $parsed = $parseExcel($response);
            $rows = $parsed['rows'];
            if ($route === 'personalTrendExport') {
                $pass = count($rows) === 5
                    && ($rows[1]['A'] ?? null) === '日期'
                    && ($rows[1]['B'] ?? null) === $metricName
                    && ($rows[2]['A'] ?? null) === $day1
                    && ($rows[3]['A'] ?? null) === $day2
                    && bccomp((string)($rows[2]['B'] ?? '0'), '70.50', 2) === 0
                    && bccomp((string)($rows[3]['B'] ?? '0'), '69.50', 2) === 0
                    && ($rows[4]['A'] ?? null) === '平均值'
                    && bccomp((string)($rows[4]['B'] ?? '0'), '70.00', 2) === 0
                    && ($rows[5]['A'] ?? null) === '标准差'
                    && bccomp((string)($rows[5]['B'] ?? '0'), '0.71', 2) === 0;
            } else {
                $pass = count($rows) === 2
                    && array_values($rows[1]) === ['姓名', '指标', '本次指标值', '本次检测日期',
                        '日变化率', '周变化率', '月变化率']
                    && ($rows[2]['A'] ?? null) === '用户' . $userId
                    && ($rows[2]['B'] ?? null) === $metricName
                    && ($rows[2]['C'] ?? null) === '69.5 kg'
                    && ($rows[2]['D'] ?? null) === $day2
                    && ($rows[2]['E'] ?? null) === '-1.42%'
                    && ($rows[2]['F'] ?? null) === '-'
                    && ($rows[2]['G'] ?? null) === '-';
            }
            $results[$route][$method] = ['status' => $pass ? 'tested-pass' : 'tested-fail',
                'file_bytes' => $parsed['bytes'], 'excel5_magic' => true,
                'source_rows' => 2];
            if (!$pass && getenv('POC_DEBUG_ROWS') === '1') {
                $results[$route][$method]['observed_rows'] = $rows;
            }
        }
    }
} finally {
    foreach ($tempFiles as $file) {
        if (is_file($file) && strpos($file, $root . '/runtime/CDXPARHEX') === 0) unlink($file);
    }
    foreach ($sessions as $sessionId) {
        $store->prepare('DELETE FROM ' . $table('health_record')
            . ' WHERE SESSION_ID=? AND AI_USER_ID=?')->execute([$sessionId, $userId]);
        $store->prepare('DELETE FROM ' . $table('measurement_session')
            . ' WHERE SESSION_ID=? AND AI_USER_ID=? AND DEVICE_MODEL=?')
            ->execute([$sessionId, $userId, $marker]);
    }
    if ($userId > 0) {
        $ai->prepare('DELETE FROM ' . $table('user', true)
            . ' WHERE USER_ID=? AND NICK_NAME=?')->execute([$userId, $marker]);
        $sourceQuery = $store->prepare('SELECT COUNT(*) FROM ' . $table('health_record')
            . ' WHERE AI_USER_ID=?');
        $sourceQuery->execute([$userId]);
        if ((int)$sourceQuery->fetchColumn() !== 0) {
            throw new RuntimeException('Health export source record cleanup failed');
        }
    }
    foreach ($tempFiles as $file) {
        if (is_file($file)) throw new RuntimeException('Health XLS verification file not removed');
    }
}
$results['cleanup'] = ['status' => 'tested-pass', 'user_rows' => 0,
    'session_rows' => 0, 'record_rows' => 0, 'temp_files' => 0];
echo json_encode(['dialect' => $dialect, 'module' => 'store-zhaiker-health-export',
    'results' => $results], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
foreach ($results as $group) {
    foreach ($group as $item) {
        if (is_array($item) && isset($item['status']) && $item['status'] !== 'tested-pass') exit(1);
    }
}
