<?php

declare(strict_types=1);

// Run only against the isolated A/B/C HTTP runtimes and the corresponding local/non-production DB.
$baseUrl = rtrim((string)getenv('POC_BASE_URL'), '/');
$dialect = (string)getenv('POC_DIALECT');
$targetRoot = (string)getenv('POC_TARGET_ROOT');
if ($baseUrl === '' || !in_array($dialect, ['mysql', 'dm'], true)) {
    throw new RuntimeException('POC_BASE_URL and POC_DIALECT=mysql|dm are required');
}

$host = (string)getenv('POC_HOST');
$port = (string)getenv('POC_PORT');
$schema = (string)getenv('POC_SCHEMA');
$user = (string)getenv('POC_USER');
$password = (string)getenv('POC_PASSWORD');
$runtimePid = (string)getenv('POC_RUNTIME_PID');
if ($dialect === 'dm' && $host === '' && ctype_digit($runtimePid)) {
    // The isolated server already owns the non-production connection settings.
    // Read only the five required values in memory; never print or persist them.
    $runtimeEnv = (string)file_get_contents('/proc/' . $runtimePid . '/environ');
    $wanted = ['POC_HOST', 'POC_PORT', 'POC_SCHEMA', 'POC_USER', 'POC_PASSWORD'];
    $found = [];
    foreach (explode("\0", $runtimeEnv) as $entry) {
        $parts = explode('=', $entry, 2);
        if (count($parts) === 2 && in_array($parts[0], $wanted, true)) {
            $found[$parts[0]] = $parts[1];
        }
    }
    $host = (string)($found['POC_HOST'] ?? '');
    $port = (string)($found['POC_PORT'] ?? '');
    $schema = (string)($found['POC_SCHEMA'] ?? '');
    $user = (string)($found['POC_USER'] ?? '');
    $password = (string)($found['POC_PASSWORD'] ?? '');
}
if ($targetRoot !== '') {
    $localConfig = $targetRoot . '/application/config/local/database.php';
    $config = require (is_file($localConfig)
        ? $localConfig
        : $targetRoot . '/application/database.php');
    if ($host === '') $host = (string)$config['hostname'];
    if ($port === '') $port = (string)($config['hostport'] ?? '3306');
    if ($schema === '') $schema = (string)$config['database'];
    if ($user === '') $user = (string)$config['username'];
    if ($password === '') $password = (string)$config['password'];
}
if ($host === '' || $schema === '' || $user === '') {
    throw new RuntimeException('Database connection configuration missing');
}
$dsn = $dialect === 'dm'
    ? "dm:host=$host;port=$port;schema=$schema"
    : "mysql:host=$host;port=$port;dbname=$schema;charset=utf8mb4";
$pdo = new PDO($dsn, $user, $password, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$table = $dialect === 'dm' ? 'YDY_BRAND_LOGO_CONFIG' : 'ydy_brand_logo_config';
$pdo->query('SELECT COUNT(*) FROM ' . $table . ' WHERE 1=0');

function brandRequest(string $url, string $method = 'GET'): array
{
    $context = stream_context_create(['http' => [
        'method' => $method,
        'timeout' => 15,
        'ignore_errors' => true,
    ]]);
    $body = file_get_contents($url, false, $context);
    if ($body === false) {
        throw new RuntimeException('HTTP request failed');
    }
    $headers = $http_response_header ?? [];
    preg_match('/HTTP\/\S+\s+(\d+)/', (string)($headers[0] ?? ''), $match);
    $status = isset($match[1]) ? (int)$match[1] : 0;
    $normalized = [];
    foreach ($headers as $header) {
        $parts = explode(':', $header, 2);
        if (count($parts) === 2) {
            $normalized[strtolower(trim($parts[0]))] = trim($parts[1]);
        }
    }
    return [$status, $normalized, $body];
}

function brandShape($value): string
{
    if (!is_array($value)) {
        return gettype($value);
    }
    $keys = array_keys($value);
    if ($keys === range(0, count($keys) - 1)) {
        return '[' . implode(',', array_map('brandShape', $value)) . ']';
    }
    sort($keys, SORT_STRING);
    $parts = [];
    foreach ($keys as $key) {
        $parts[] = $key . ':' . brandShape($value[$key]);
    }
    return '{' . implode(',', $parts) . '}';
}

$select = $pdo->prepare('SELECT ASSET_TYPE,SYSTEM_NAME,FILE_PATH,UPDATE_TIME FROM ' . $table
    . ' WHERE BUSINESS_CODE=? AND STORE_ID=? AND TERMINAL_CODE=?');
$results = [];
$pcData = null;
foreach (['pc', '103'] as $terminal) {
    list($status, $headers, $body) = brandRequest($baseUrl . '/api/brandLogo/config?terminal=' . $terminal);
    $json = json_decode($body, true);
    if ($status !== 200 || !is_array($json) || ($json['code'] ?? null) !== 0
        || ($json['message'] ?? null) !== '' || !is_array($json['data'] ?? null)
        || ($headers['access-control-allow-origin'] ?? null) !== '*') {
        throw new RuntimeException('Brand GET success contract mismatch: ' . $terminal);
    }
    $data = $json['data'];
    if (($data['terminal_code'] ?? null) !== $terminal
        || !is_string($data['business_code'] ?? null)
        || !is_int($data['store_id'] ?? null)) {
        throw new RuntimeException('Brand GET identity/types mismatch: ' . $terminal);
    }
    $select->execute([$data['business_code'], $data['store_id'], $terminal]);
    $rows = array_map(static function (array $row): array {
        return array_change_key_case($row, CASE_LOWER);
    }, $select->fetchAll(PDO::FETCH_ASSOC));
    $byType = [];
    $updatedAt = '';
    foreach ($rows as $row) {
        $byType[(string)$row['asset_type']] = $row;
        if ((string)$row['update_time'] > $updatedAt) {
            $updatedAt = (string)$row['update_time'];
        }
    }
    $expectedName = trim((string)($byType['system_name']['system_name'] ?? ''));
    if (($data['system_name'] ?? null) !== $expectedName
        || ($data['updated_at'] ?? null) !== $updatedAt) {
        throw new RuntimeException('Brand GET metadata/database readback mismatch: ' . $terminal);
    }
    $map = [
        'logo_url' => 'logo',
        'header_logo_url' => 'header_logo',
        'favicon_url' => 'favicon',
        'dark_logo_url' => 'dark_logo',
        'light_logo_url' => 'light_logo',
    ];
    foreach ($map as $field => $asset) {
        if (!array_key_exists($field, $data) || !is_string($data[$field])) {
            throw new RuntimeException('Brand GET URL field/type mismatch: ' . $field);
        }
        $path = trim((string)($byType[$asset]['file_path'] ?? ''));
        if ($path === '' ? $data[$field] !== '' : substr($data[$field], -strlen($path)) !== $path) {
            throw new RuntimeException('Brand GET asset/database readback mismatch: ' . $field);
        }
    }
    $results[$terminal] = [
        'status' => 'tested-pass',
        'db_rows' => count($rows),
        'shape_sha256' => hash('sha256', brandShape($json)),
    ];
    if ($terminal === 'pc') {
        $pcData = $data;
    }
}

list($defaultStatus, , $defaultBody) = brandRequest($baseUrl . '/api/brandLogo/config');
$default = json_decode($defaultBody, true);
if ($defaultStatus !== 200 || !is_array($default) || ($default['code'] ?? null) !== 0
    || ($default['data']['terminal_code'] ?? null) !== 'pc' || $default['data'] !== $pcData) {
    throw new RuntimeException('Brand GET default terminal mismatch');
}
$results['default_terminal'] = ['status' => 'tested-pass', 'matches_pc' => true];

list($invalidStatus, , $invalidBody) = brandRequest($baseUrl . '/api/brandLogo/config?terminal=invalid-terminal');
$invalid = json_decode($invalidBody, true);
if ($invalidStatus !== 200 || !is_array($invalid) || ($invalid['code'] ?? null) !== 1
    || ($invalid['message'] ?? null) !== '不支持的终端类型' || ($invalid['data'] ?? null) !== []) {
    throw new RuntimeException('Brand GET invalid terminal contract mismatch');
}
$results['invalid_terminal'] = ['status' => 'tested-pass', 'shape_sha256' => hash('sha256', brandShape($invalid))];

list($optionsStatus, $optionsHeaders, $optionsBody) = brandRequest($baseUrl . '/api/brandLogo/config', 'OPTIONS');
if ($optionsStatus !== 204
    || ($optionsHeaders['access-control-allow-origin'] ?? null) !== '*'
    || ($optionsHeaders['access-control-allow-methods'] ?? null) !== 'GET, OPTIONS') {
    throw new RuntimeException('Brand OPTIONS contract mismatch');
}
$results['options'] = [
    'status' => $optionsBody === '' ? 'tested-pass' : 'tested-fail',
    'http_status' => $optionsStatus,
    'body_bytes' => strlen($optionsBody),
    'debug_trace_leak' => strpos($optionsBody, 'think_page_trace') !== false,
];

// One clearly marked, isolated row exercises the non-empty numeric-terminal DB path.
// The row is committed for the separate HTTP connection and removed by exact UUID.
$marker = 'CDXPARST' . strtoupper(bin2hex(random_bytes(9)));
$terminal = '9' . (string)random_int(100000000, 999999999);
$path = 'static/upload/brandLogo/' . $marker . '.png';
$countFixture = $pdo->prepare('SELECT COUNT(*) FROM ' . $table . ' WHERE UUID=?');
$readTime = $pdo->prepare('SELECT UPDATE_TIME FROM ' . $table . ' WHERE UUID=?');
$countFixture->execute([$marker]);
if ((int)$countFixture->fetchColumn() !== 0) {
    throw new RuntimeException('Brand fixture UUID already exists');
}
$insert = $pdo->prepare('INSERT INTO ' . $table
    . ' (UUID,BUSINESS_CODE,STORE_ID,TERMINAL_CODE,ASSET_TYPE,SYSTEM_NAME,FILE_PATH,'
    . ' SOURCE_FILE_PATH,FILE_NAME,MIME_TYPE,FILE_SIZE,IMAGE_WIDTH,IMAGE_HEIGHT,'
    . ' CREATE_BY,CREATE_BY_UUID,UPDATE_BY,UPDATE_BY_UUID,CREATE_TIME,UPDATE_TIME)'
    . ' VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)');
$delete = $pdo->prepare('DELETE FROM ' . $table . ' WHERE UUID=?');
$now = date('Y-m-d H:i:s');
try {
    $insert->execute([$marker, $pcData['business_code'], $pcData['store_id'], $terminal,
        'dark_logo', '', $path, $path, $marker . '.png', 'image/png', 10, 1, 1,
        $marker, $marker, $marker, $marker, $now, $now]);
    list($fixtureStatus, , $fixtureBody) = brandRequest($baseUrl
        . '/api/brandLogo/config?terminal=' . $terminal);
    $fixture = json_decode($fixtureBody, true);
    $countFixture->execute([$marker]);
    $storedCount = (int)$countFixture->fetchColumn();
    $readTime->execute([$marker]);
    $storedTime = $readTime->fetchColumn();
    $checks = [
        'http_200' => $fixtureStatus === 200,
        'json' => is_array($fixture),
        'code_0' => ($fixture['code'] ?? null) === 0,
        'terminal' => ($fixture['data']['terminal_code'] ?? null) === $terminal,
        'url_type' => is_string($fixture['data']['dark_logo_url'] ?? null),
        'url_suffix' => is_string($fixture['data']['dark_logo_url'] ?? null)
            && substr($fixture['data']['dark_logo_url'], -strlen($path)) === $path,
        'updated_at' => ($fixture['data']['updated_at'] ?? null) === $now,
        'db_count_1' => $storedCount === 1,
    ];
    $results['synthetic_nonempty'] = [
        'status' => in_array(false, $checks, true) ? 'tested-fail' : 'tested-pass',
        'db_rows' => $storedCount,
        'checks' => $checks,
        'insert_time' => $now,
        'db_time' => (string)$storedTime,
        'db_time_php_type' => gettype($storedTime),
        'response_time' => $fixture['data']['updated_at'] ?? null,
        'response_time_json_type' => gettype($fixture['data']['updated_at'] ?? null),
        'timestamp_has_fraction' => preg_match('/\.\d+$/', (string)($fixture['data']['updated_at'] ?? '')) === 1,
        'shape_sha256' => is_array($fixture) ? hash('sha256', brandShape($fixture)) : null,
    ];
} finally {
    $delete->execute([$marker]);
    $countFixture->execute([$marker]);
    if ((int)$countFixture->fetchColumn() !== 0) {
        throw new RuntimeException('Brand fixture cleanup failed');
    }
}
$results['synthetic_cleanup'] = ['status' => 'tested-pass', 'remaining_rows' => 0];

echo json_encode(['dialect' => $dialect, 'module' => 'store-public-brand-logo',
    'results' => $results], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
