<?php

declare(strict_types=1);

$root = (string)getenv('POC_TARGET_ROOT');
$base = rtrim((string)getenv('POC_BASE_URL'), '/');
$dialect = (string)getenv('POC_DIALECT');
$variant = (string)getenv('POC_VARIANT');
$runtimes = [
    'A' => ['/tmp/zhct-http-ai-macos.zjaU8h', 'http://127.0.0.1:18105', 'mysql'],
    'B' => ['/tmp/zhct-http-ai-macos.x2CCZX', 'http://127.0.0.1:18101', 'mysql'],
    'C' => ['/tmp/zhct-ai-http-20260929.3XDj3w', 'http://127.0.0.1:18102', 'dm'],
];
if (!isset($runtimes[$variant]) || [$root, $base, $dialect] !== $runtimes[$variant]
    || !is_file($root . '/vendor/autoload.php')) {
    throw new RuntimeException('Approved isolated AI feedback runtime required');
}
if ($dialect === 'dm') {
    $pid = (string)getenv('POC_RUNTIME_PID');
    if (!ctype_digit($pid) || (int)$pid <= 1) throw new RuntimeException('AI HTTP PID missing');
    $processEnv = [];
    foreach (explode("\0", (string)@file_get_contents('/proc/' . $pid . '/environ')) as $item) {
        $parts = explode('=', $item, 2);
        if (count($parts) === 2) $processEnv[$parts[0]] = $parts[1];
    }
    if (($processEnv['POC_TARGET_ROOT'] ?? '') !== $root
        || ($processEnv['POC_BASE_URL'] ?? '') !== $base
        || ($processEnv['POC_DIALECT'] ?? '') !== 'dm') {
        throw new RuntimeException('AI HTTP process identity mismatch');
    }
    foreach (['POC_AI_HOST', 'POC_AI_PORT', 'POC_AI_SCHEMA', 'POC_AI_USER',
        'POC_AI_PASSWORD'] as $key) {
        if (empty($processEnv[$key])) throw new RuntimeException('AI HTTP DB context missing');
        putenv($key . '=' . $processEnv[$key]);
    }
    if ((string)getenv('POC_AI_PORT') !== '5238'
        || (string)getenv('POC_AI_SCHEMA') !== 'AIZHCT_APP'
        || (string)getenv('POC_AI_USER') !== 'AIZHCT_APP') {
        throw new RuntimeException('AI non-production DM account boundary failed');
    }
} else {
    $approved = '/Users/wiscourper/Documents/workspace/zhct/zhctproject/ai_api/.env.local';
    $path = (string)getenv('POC_MYSQL_LOCAL_ENV');
    if (realpath($path) === false || realpath($path) !== realpath($approved)) {
        throw new RuntimeException('Only AI code local MySQL configuration allowed');
    }
    $local = parse_ini_file($path, true, INI_SCANNER_RAW);
    if (!is_array($local) || !isset($local['DATABASE'])) {
        throw new RuntimeException('AI code local MySQL configuration absent');
    }
    foreach (['HOSTNAME' => 'HOST', 'HOSTPORT' => 'PORT', 'DATABASE' => 'SCHEMA',
        'USERNAME' => 'USER', 'PASSWORD' => 'PASSWORD'] as $from => $to) {
        putenv('POC_AI_' . $to . '=' . (string)$local['DATABASE'][$from]);
    }
}
$boundaryRaw = @file_get_contents($base . '/__poc_boundary', false,
    stream_context_create(['http' => ['timeout' => 5]]));
$boundary = is_string($boundaryRaw) ? json_decode($boundaryRaw, true) : null;
if (!is_array($boundary) || empty($boundary['external_stubs'])) {
    throw new RuntimeException('AI HTTP external isolation absent');
}

define('TP_ENV', 'poc');
define('BUSINESS', 'aizhct');
define('ENTERPRISE_NO', '10001');
require $root . '/vendor/autoload.php';
(new \think\App($root))->setEnvName('poc')->initialize();
$dsn = $dialect === 'dm'
    ? 'dm:host=' . getenv('POC_AI_HOST') . ';port=' . getenv('POC_AI_PORT')
        . ';schema=' . getenv('POC_AI_SCHEMA')
    : 'mysql:host=' . getenv('POC_AI_HOST') . ';port=' . getenv('POC_AI_PORT')
        . ';dbname=' . getenv('POC_AI_SCHEMA') . ';charset=utf8mb4';
$db = new PDO($dsn, getenv('POC_AI_USER'), getenv('POC_AI_PASSWORD'),
    [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_CASE => PDO::CASE_LOWER, PDO::ATTR_TIMEOUT => 5]);
if ($dialect === 'dm') {
    if ((string)$db->query("SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL")
        ->fetchColumn() !== 'AIZHCT_APP') {
        throw new RuntimeException('Effective AI DM schema mismatch');
    }
}
$table = static function (string $name) use ($dialect): string {
    return $dialect === 'dm' ? strtoupper($name) : $name;
};
$userTable = $table('yoshop_user');
$feedbackTable = $table('yoshop_user_feedback');
$storeTable = $table('yoshop_store');
$count = static function (string $sql, array $args = []) use ($db): int {
    $statement = $db->prepare($sql);
    $statement->execute($args);
    return (int)$statement->fetchColumn();
};
$rows = static function (string $sql, array $args = []) use ($db): array {
    $statement = $db->prepare($sql);
    $statement->execute($args);
    return $statement->fetchAll(PDO::FETCH_ASSOC);
};
$assert = static function (bool $ok, string $message): void {
    if (!$ok) throw new RuntimeException($message);
};
foreach ([$userTable, $feedbackTable, $storeTable] as $required) {
    $db->query('SELECT 1 FROM ' . $required . ' WHERE 1=0');
}
$requiredColumns = [
    $feedbackTable => ['ID', 'USER_ID', 'STORE_ID', 'STATUS', 'CATE', 'CONTENTS', 'IMAGES',
        'CREATE_TIME', 'UPDATE_TIME'],
    $userTable => ['USER_ID', 'STORE_ID', 'NICK_NAME', 'IS_DELETE', 'CREATE_TIME'],
];
foreach ($requiredColumns as $name => $fields) {
    $statement = $dialect === 'dm'
        ? $db->prepare('SELECT COLUMN_NAME FROM USER_TAB_COLUMNS WHERE TABLE_NAME=?')
        : $db->prepare('SELECT COLUMN_NAME FROM information_schema.COLUMNS'
            . ' WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=?');
    $statement->execute([$name]);
    $actual = array_map('strtoupper', $statement->fetchAll(PDO::FETCH_COLUMN));
    $assert(count(array_diff($fields, $actual)) === 0,
        'Required AI feedback columns missing');
}
$assert($count('SELECT COUNT(*) FROM ' . $storeTable
    . ' WHERE STORE_ID=? AND IS_DELETE=0', [10001]) === 1,
    'Approved AI store row missing/ambiguous');
if ((string)getenv('POC_APPROVED_FEEDBACK_WRITE') !== '1') {
    echo json_encode(['suite' => 'feedback-' . $variant,
        'mode' => 'read-only-preflight', 'required_tables_present' => true,
        'external_stubs' => true], JSON_UNESCAPED_SLASHES) . PHP_EOL;
    exit(0);
}

$marker = 'CDXPARFB' . strtoupper(bin2hex(random_bytes(4)));
$content = $marker . '-feedback';
$token = $marker . 'TOKEN' . strtoupper(bin2hex(random_bytes(10)));
$userId = 0;
$results = [];
$cleanup = [];
$failure = '';
$request = static function (?string $auth, array $form) use ($base): array {
    $headers = "platform: POC\r\nContent-Type: application/json;charset=utf-8\r\n";
    if ($auth !== null) $headers .= 'Access-Token: ' . $auth . "\r\n";
    $context = stream_context_create(['http' => [
        'method' => 'POST', 'header' => $headers,
        'content' => json_encode(['form' => $form], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
        'timeout' => 30, 'ignore_errors' => true,
    ]]);
    $raw = @file_get_contents($base . '/api/user.userFeedback/add?storeId=10001',
        false, $context);
    $httpLine = $http_response_header[0] ?? '';
    preg_match('/HTTP\/\S+\s+(\d+)/', $httpLine, $match);
    $body = is_string($raw) ? json_decode($raw, true) : null;
    return ['http' => isset($match[1]) ? (int)$match[1] : 0,
        'status' => is_array($body) ? (int)($body['status'] ?? -1) : -1,
        'message' => is_array($body) ? (string)($body['message'] ?? '') : '',
        'data_empty' => is_array($body) && ($body['data'] ?? null) === []];
};
try {
    $assert($count('SELECT COUNT(*) FROM ' . $userTable
        . ' WHERE NICK_NAME=?', [$marker]) === 0
        && $count('SELECT COUNT(*) FROM ' . $feedbackTable
            . ' WHERE CONTENTS=?', [$content]) === 0,
        'Synthetic feedback marker already exists');
    $db->prepare('INSERT INTO ' . $userTable
        . ' (STORE_ID,MOBILE,NICK_NAME,BALANCE,GIFT_BALANCE,IS_DELETE,CREATE_TIME)'
        . ' VALUES (10001,?,?,?,?,0,?)')
        ->execute(['', $marker, '0.00', '0.00', time()]);
    $userRows = $rows('SELECT USER_ID FROM ' . $userTable
        . ' WHERE NICK_NAME=?', [$marker]);
    $assert(count($userRows) === 1, 'Synthetic feedback user missing/ambiguous');
    $userId = (int)$userRows[0]['user_id'];
    $assert($userId > 0 && $count('SELECT COUNT(*) FROM ' . $feedbackTable
        . ' WHERE USER_ID=?', [$userId]) === 0,
        'Synthetic feedback user preexisting rows');
    \think\facade\Cache::set($token, ['user' => ['user_id' => $userId],
        'password_version' => 0, 'login_type' => 'thirdparty'], 300);

    $form = ['cate' => 3, 'contents' => $content, 'images' => []];
    $unauth = $request(null, $form);
    $assert($unauth['status'] === 401 && $count('SELECT COUNT(*) FROM ' . $feedbackTable
        . ' WHERE USER_ID=?', [$userId]) === 0,
        'Unauthenticated feedback wrote rows');
    $results['unauth_rejected_zero_write'] = true;

    $invalid = $request($token, array_replace($form, ['cate' => 0]));
    $assert($invalid['status'] !== 200 && $count('SELECT COUNT(*) FROM ' . $feedbackTable
        . ' WHERE USER_ID=?', [$userId]) === 0,
        'Invalid category accepted or wrote rows');
    $results['invalid_category_rejected_zero_write'] = true;

    $created = $request($token, $form);
    $saved = $rows('SELECT ID,USER_ID,STORE_ID,STATUS,CATE,CONTENTS,IMAGES,CREATE_TIME,UPDATE_TIME'
        . ' FROM ' . $feedbackTable . ' WHERE USER_ID=? AND CONTENTS=?',
        [$userId, $content]);
    $source = $saved[0] ?? [];
    $diagnostics = [
        'http_200' => $created['http'] === 200,
        'business_200' => $created['status'] === 200,
        'message_submit_success' => $created['message'] === '提交成功',
        'message_submit_failure' => $created['message'] === '提交失败',
        'response_data_empty' => $created['data_empty'],
        'source_one_row' => count($saved) === 1,
        'source_id_positive' => (int)($source['id'] ?? 0) > 0,
        'source_id_type' => gettype($source['id'] ?? null),
        'source_user_match' => (int)($source['user_id'] ?? 0) === $userId,
        'source_store_match' => (int)($source['store_id'] ?? 0) === 10001,
        'source_status_zero' => (int)($source['status'] ?? -1) === 0,
        'source_category_three' => (int)($source['cate'] ?? 0) === 3,
        'source_contents_match' => (string)($source['contents'] ?? '') === $content,
        'source_images_json_empty' => (string)($source['images'] ?? '') === '[]',
        'source_created_at_positive' => (int)($source['create_time'] ?? 0) > 0,
        'source_updated_at_positive' => (int)($source['update_time'] ?? 0) > 0,
    ];
    $results['positive_diagnostics'] = $diagnostics;
    $assert($diagnostics['http_200'] && $diagnostics['business_200']
        && $diagnostics['message_submit_success'] && $diagnostics['response_data_empty']
        && $diagnostics['source_one_row'] && $diagnostics['source_id_positive']
        && $diagnostics['source_user_match'] && $diagnostics['source_store_match']
        && $diagnostics['source_status_zero'] && $diagnostics['source_category_three']
        && $diagnostics['source_contents_match'] && $diagnostics['source_images_json_empty']
        && $diagnostics['source_created_at_positive'] && $diagnostics['source_updated_at_positive'],
        'Feedback success message/source row mismatch');
    $results['feedback_one_row_payload_and_response'] = true;
} catch (Throwable $e) {
    $failure = get_class($e) . ':' . hash('sha256', $e->getMessage());
} finally {
    try {
        \think\facade\Cache::delete($token);
        if ($userId > 0) {
            $owned = $rows('SELECT ID,USER_ID,CATE,CONTENTS FROM ' . $feedbackTable
                . ' WHERE USER_ID=?', [$userId]);
            foreach ($owned as $row) {
                if ((int)$row['cate'] !== 3 || (string)$row['contents'] !== $content) {
                    throw new RuntimeException('Unexpected synthetic feedback row; refusing cleanup');
                }
            }
            foreach ($owned as $row) {
                $db->prepare('DELETE FROM ' . $feedbackTable
                    . ' WHERE ID=? AND USER_ID=? AND CATE=? AND CONTENTS=?')
                    ->execute([(int)$row['id'], $userId, 3, $content]);
            }
            $db->prepare('DELETE FROM ' . $userTable . ' WHERE USER_ID=? AND NICK_NAME=?')
                ->execute([$userId, $marker]);
        }
        $cleanup = [
            'feedback_zero' => $count('SELECT COUNT(*) FROM ' . $feedbackTable
                . ' WHERE CONTENTS=?', [$content]) === 0,
            'user_zero' => $count('SELECT COUNT(*) FROM ' . $userTable
                . ' WHERE NICK_NAME=?', [$marker]) === 0,
        ];
    } catch (Throwable $e) {
        $cleanup['error_class'] = get_class($e);
        $cleanup['error_sha256'] = hash('sha256', $e->getMessage());
    }
}
$clean = ($cleanup['feedback_zero'] ?? false) && ($cleanup['user_zero'] ?? false);
echo json_encode(['suite' => 'feedback-' . $variant,
    'marker' => $marker, 'results' => $results, 'failure' => $failure,
    'cleanup' => $cleanup], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
if ($failure !== '' || !$clean) exit(1);
