<?php

declare(strict_types=1);

// A/B/C isolated Store runtime only. Synthetic terminal rows are deleted in finally.
$baseUrl = rtrim((string)getenv('POC_BASE_URL'), '/');
$dialect = (string)getenv('POC_DIALECT');
$root = (string)getenv('POC_APP_ROOT');
if ($baseUrl === '' || !in_array($dialect, ['mysql', 'dm'], true)
    || !is_file($root . '/application/base/Security.php')) {
    throw new RuntimeException('Isolated Store HTTP runtime configuration missing');
}
$boundary = json_decode((string)file_get_contents($baseUrl . '/__poc_boundary'), true);
if (!is_array($boundary) || empty($boundary['external_stubs'])
    || empty($boundary['redis_isolated'])) {
    throw new RuntimeException('POC isolation boundary absent');
}

$env = [];
foreach (['POC_HOST', 'POC_PORT', 'POC_SCHEMA', 'POC_USER', 'POC_PASSWORD'] as $key) {
    $env[$key] = (string)getenv($key);
}
$runtimePid = (string)getenv('POC_RUNTIME_PID');
if ($dialect === 'dm' && $env['POC_HOST'] === '' && ctype_digit($runtimePid)) {
    $raw = (string)file_get_contents('/proc/' . $runtimePid . '/environ');
    foreach (explode("\0", $raw) as $entry) {
        $parts = explode('=', $entry, 2);
        if (count($parts) === 2 && array_key_exists($parts[0], $env)) {
            $env[$parts[0]] = $parts[1];
        }
    }
}
if ($dialect === 'mysql' && $env['POC_HOST'] === '') {
    $local = $root . '/application/config/local/database.php';
    $config = require (is_file($local) ? $local : $root . '/application/database.php');
    $env = [
        'POC_HOST' => (string)$config['hostname'],
        'POC_PORT' => (string)($config['hostport'] ?? '3306'),
        'POC_SCHEMA' => (string)$config['database'],
        'POC_USER' => (string)$config['username'],
        'POC_PASSWORD' => (string)$config['password'],
    ];
}
if ($env['POC_HOST'] === '' || $env['POC_SCHEMA'] === '' || $env['POC_USER'] === '') {
    throw new RuntimeException('POC DB configuration missing');
}
$dsn = $dialect === 'dm'
    ? "dm:host={$env['POC_HOST']};port={$env['POC_PORT']};schema={$env['POC_SCHEMA']}"
    : "mysql:host={$env['POC_HOST']};port={$env['POC_PORT']};dbname={$env['POC_SCHEMA']};charset=utf8mb4";
$pdo = new PDO($dsn, $env['POC_USER'], $env['POC_PASSWORD'],
    [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$table = $dialect === 'dm' ? 'YDY_BRAND_LOGO_CONFIG' : 'ydy_brand_logo_config';

require_once $root . '/application/base/Security.php';
$marker = 'CDXPARSTADM' . strtoupper(bin2hex(random_bytes(6)));
$displayName = $marker . '测试';
$terminal = '9' . (string)random_int(100000000, 999999999);
$token = \app\base\Security::encrypt(implode("\t", ['0', $marker, $marker, '0', '', '', $marker]));
$request = static function (string $route, array $form = [], bool $auth = true) use ($baseUrl, $token): array {
    $headers = "Content-Type: application/x-www-form-urlencoded\r\n";
    if ($auth) $headers .= 'token: ' . $token . "\r\n";
    $context = stream_context_create(['http' => [
        'method' => 'POST',
        'header' => $headers,
        'content' => http_build_query($form, '', '&', PHP_QUERY_RFC3986),
        'timeout' => 20,
        'ignore_errors' => true,
    ]]);
    $body = file_get_contents($baseUrl . $route, false, $context);
    $responseHeaders = $http_response_header ?? [];
    $status = (string)($responseHeaders[0] ?? '');
    $contentType = '';
    foreach ($responseHeaders as $header) {
        if (stripos($header, 'Content-Type:') === 0) $contentType = $header;
    }
    if (strpos($status, ' 200 ') === false
        || stripos($contentType, 'application/json') === false) {
        throw new RuntimeException('Admin brand HTTP status/content type mismatch');
    }
    $response = is_string($body) ? json_decode($body, true) : null;
    if (!is_array($response)) throw new RuntimeException('Admin brand HTTP response not JSON');
    return $response;
};
$shape = static function ($value) use (&$shape): string {
    if (!is_array($value)) return gettype($value);
    $keys = array_keys($value);
    if ($keys === range(0, count($keys) - 1)) {
        return '[' . implode(',', array_map($shape, $value)) . ']';
    }
    sort($keys, SORT_STRING);
    $parts = [];
    foreach ($keys as $key) $parts[] = $key . ':' . $shape($value[$key]);
    return '{' . implode(',', $parts) . '}';
};
$readRows = static function () use ($pdo, $table, $terminal): array {
    $stmt = $pdo->prepare('SELECT ID,UUID,BUSINESS_CODE,STORE_ID,TERMINAL_CODE,ASSET_TYPE,'
        . ' SYSTEM_NAME,FILE_PATH,UPDATE_TIME FROM ' . $table . ' WHERE TERMINAL_CODE=? ORDER BY ID');
    $stmt->execute([$terminal]);
    return array_map(static function (array $row): array {
        return array_change_key_case($row, CASE_LOWER);
    }, $stmt->fetchAll(PDO::FETCH_ASSOC));
};
$preexisting = $readRows();
if ($preexisting !== []) throw new RuntimeException('Reserved synthetic terminal already exists');
$delete = $pdo->prepare('DELETE FROM ' . $table . ' WHERE TERMINAL_CODE=?');
$results = [];
$asset = static function (string $type, string $path, string $marker): array {
    return [
        'asset_type' => $type,
        'file_path' => $path,
        'source_file_path' => $path,
        'file_name' => $marker . '.png',
        'mime_type' => 'image/png',
        'file_size' => 10,
        'image_width' => 1,
        'image_height' => 1,
    ];
};
$darkPath = 'static/upload/brandLogo/' . $marker . '-dark.png';
$lightPath = 'static/upload/brandLogo/' . $marker . '-light.png';
$byType = static function (array $rows): array {
    $map = [];
    foreach ($rows as $row) $map[$row['asset_type']] = $row;
    return $map;
};
try {
    $anonymous = $request('/p/brandLogo/configs', [], false);
    $results['anonymous_configs'] = [
        'status' => (int)($anonymous['code'] ?? -1) === 100 ? 'tested-pass' : 'tested-fail',
        'code' => $anonymous['code'] ?? null,
        'message' => $anonymous['msg'] ?? $anonymous['message'] ?? null,
    ];

    $baseline = $request('/p/brandLogo/configs');
    if ((int)($baseline['code'] ?? -1) !== 0
        || !is_array($baseline['data']['terminals'] ?? null)
        || !is_int($baseline['data']['store_id'] ?? null)
        || !is_string($baseline['data']['business_code'] ?? null)) {
        throw new RuntimeException('Admin configs baseline failed');
    }
    $results['configs_baseline'] = ['status' => 'tested-pass',
        'terminal_count' => count($baseline['data']['terminals'])];

    $missing = $request('/p/brandLogo/save', ['assets' => '{}']);
    $badPath = $request('/p/brandLogo/save', ['terminal_code' => $terminal,
        'assets' => json_encode(['dark_logo' => $asset('dark_logo', '../bad.png', $marker)])]);
    $results['invalid_no_mutation'] = [
        'status' => (int)($missing['code'] ?? 0) !== 0
            && (int)($badPath['code'] ?? 0) !== 0 && $readRows() === []
            ? 'tested-pass' : 'tested-fail',
        'missing_code' => $missing['code'] ?? null,
        'missing_message' => $missing['message'] ?? null,
        'bad_path_code' => $badPath['code'] ?? null,
        'bad_path_message' => $badPath['message'] ?? null,
    ];

    $first = $request('/p/brandLogo/save', [
        'terminal_code' => $terminal,
        'system_name' => $displayName,
        'assets' => json_encode(['dark_logo' => $asset('dark_logo', $darkPath, $marker)]),
    ]);
    $rows = $readRows();
    $map = $byType($rows);
    $initial = (int)($first['code'] ?? -1) === 0 && count($rows) === 2
        && ($map['dark_logo']['file_path'] ?? null) === $darkPath
        && ($map['system_name']['system_name'] ?? null) === $displayName
        && ($first['data']['terminal_code'] ?? null) === $terminal
        && ($first['data']['system_name'] ?? null) === $displayName
        && is_string($first['data']['assets']['dark_logo']['url'] ?? null)
        && substr($first['data']['assets']['dark_logo']['url'], -strlen($darkPath)) === $darkPath;
    $results['save_insert'] = ['status' => $initial ? 'tested-pass' : 'tested-fail',
        'db_rows' => count($rows), 'code' => $first['code'] ?? null,
        'shape_sha256' => hash('sha256', $shape($first))];
    if (!$initial) throw new RuntimeException('Initial admin save did not establish safe fixture');

    $configs = $request('/p/brandLogo/configs');
    $matches = array_values(array_filter((array)($configs['data']['terminals'] ?? []),
        static function ($item) use ($terminal): bool {
            return is_array($item) && (string)($item['terminal_code'] ?? '') === $terminal;
        }));
    $results['configs_nonempty'] = [
        'status' => (int)($configs['code'] ?? -1) === 0 && count($matches) === 1
            && ($matches[0]['system_name'] ?? null) === $displayName
            && ($matches[0]['assets']['dark_logo']['file_path'] ?? null) === $darkPath
            ? 'tested-pass' : 'tested-fail',
        'matching_terminal_rows' => count($matches),
    ];

    $repeat = $request('/p/brandLogo/save', [
        'terminal_code' => $terminal,
        'system_name' => $displayName,
        'assets' => ['dark_logo' => $asset('dark_logo', $darkPath, $marker)],
    ]);
    $repeatCount = count($readRows());
    $results['repeat_save'] = ['status' => (int)($repeat['code'] ?? -1) === 0
        && $repeatCount === 2 ? 'tested-pass' : 'tested-fail',
        'code' => $repeat['code'] ?? null,
        'message' => $repeat['message'] ?? null,
        'db_rows' => $repeatCount];

    $renamed = $displayName . '更新';
    $partial = $request('/p/brandLogo/save', [
        'terminal_code' => $terminal, 'system_name' => $renamed, 'assets' => '{}',
    ]);
    $map = $byType($readRows());
    $results['partial_update'] = [
        'status' => (int)($partial['code'] ?? -1) === 0 && count($map) === 2
            && ($map['dark_logo']['file_path'] ?? null) === $darkPath
            && ($map['system_name']['system_name'] ?? null) === $renamed
            ? 'tested-pass' : 'tested-fail',
    ];

    $light = $request('/p/brandLogo/save', [
        'terminal_code' => $terminal,
        'assets' => json_encode(['light_logo' => $asset('light_logo', $lightPath, $marker)]),
    ]);
    $map = $byType($readRows());
    $results['second_asset'] = [
        'status' => (int)($light['code'] ?? -1) === 0 && count($map) === 3
            && ($map['light_logo']['file_path'] ?? null) === $lightPath
            && ($map['dark_logo']['file_path'] ?? null) === $darkPath
            ? 'tested-pass' : 'tested-fail',
    ];

    $badAsset = $request('/p/brandLogo/save', [
        'terminal_code' => $terminal,
        'assets' => json_encode(['favicon' => $asset('favicon', $lightPath, $marker)]),
    ]);
    $results['invalid_asset_no_mutation'] = [
        'status' => (int)($badAsset['code'] ?? 0) !== 0 && count($readRows()) === 3
            ? 'tested-pass' : 'tested-fail',
        'message' => $badAsset['message'] ?? null,
    ];

    $clearDark = $request('/p/brandLogo/clear', [
        'terminal_code' => $terminal, 'asset_type' => 'dark_logo',
    ]);
    $map = $byType($readRows());
    $results['clear_one'] = [
        'status' => (int)($clearDark['code'] ?? -1) === 0 && count($map) === 2
            && !isset($map['dark_logo']) && isset($map['light_logo'], $map['system_name'])
            ? 'tested-pass' : 'tested-fail',
        'shape_sha256' => hash('sha256', $shape($clearDark)),
    ];

    $clearAll = $request('/p/brandLogo/clear', ['terminal_code' => $terminal]);
    $repeatClear = $request('/p/brandLogo/clear', ['terminal_code' => $terminal]);
    $results['clear_all_idempotent'] = [
        'status' => (int)($clearAll['code'] ?? -1) === 0
            && (int)($repeatClear['code'] ?? -1) === 0 && $readRows() === []
            ? 'tested-pass' : 'tested-fail',
        'remaining_rows' => count($readRows()),
        'shape_sha256' => hash('sha256', $shape($clearAll)),
    ];

    $anonymousSave = $request('/p/brandLogo/save', [
        'terminal_code' => $terminal, 'system_name' => $marker,
    ], false);
    $results['anonymous_save_no_mutation'] = [
        'status' => (int)($anonymousSave['code'] ?? -1) === 100 && $readRows() === []
            ? 'tested-pass' : 'tested-fail',
    ];
} finally {
    $delete->execute([$terminal]);
    if ($readRows() !== []) throw new RuntimeException('Synthetic brand admin rows not cleaned');
}
$results['final_cleanup'] = ['status' => 'tested-pass', 'remaining_rows' => 0];
echo json_encode(['dialect' => $dialect, 'module' => 'store-brand-admin',
    'results' => $results], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
