<?php

declare(strict_types=1);

$root = getenv('POC_APP_ROOT');
$dialect = getenv('POC_DIALECT');
$host = getenv('POC_HOST');
$port = (int)getenv('POC_PORT');
$schema = getenv('POC_SCHEMA');
$user = getenv('POC_USER');
$password = getenv('POC_PASSWORD');
if (!$root || !in_array($dialect, ['mysql', 'dm'], true) || !$host || $port < 1 || !$schema || !$user || !$password) exit(2);
define('APP_PATH', $root . '/application/');
require $root . '/thinkphp/base.php';
require $root . '/application/common.php';
if (!function_exists('config')) {
    function config($name = '', $value = null, $range = '')
    {
        return $value === null ? \think\Config::get($name) : \think\Config::set($name, $value, $range);
    }
}
if (!function_exists('json')) {
    function json($data = [], $code = 200, array $header = [], $options = [])
    {
        return \think\Response::create($data, 'json', $code, $header, $options);
    }
}

\think\Config::set([
    'type' => $dialect === 'dm' ? \app\cores\database\Dm::class : 'mysql',
    'hostname' => $host,
    'hostport' => $port,
    'database' => $schema,
    'username' => $user,
    'password' => $password,
    'prefix' => 'ydy_',
    'debug' => false,
    'resultset_type' => 'array',
    'fields_strict' => true,
    'auto_timestamp' => false,
], 'database');
\think\Db::clear();

$tables = array_map('strtolower', \think\Db::connect()->getTables());
foreach (['ydy_dish_questionnaire', 'ydy_dish_questionnaire_tag', 'ydy_restaurants', 'ydy_dishes'] as $table) {
    if (!in_array($table, $tables, true)) throw new RuntimeException('Required business table missing: ' . $table);
}
$storeId = (int)getStoreId();
$restaurant = \think\Db::name('restaurants')->where(['status' => 1, 'is_delete' => 2])->order('id', 'asc')->find();
$dish = \think\Db::name('dishes')->where(['store_id' => $storeId, 'status' => 1, 'is_del' => 1, 'is_delete' => 0])->order('id', 'asc')->find();
if (!$restaurant || !$dish) {
    echo json_encode(['dialect' => $dialect, 'status' => 'fixture_missing', 'restaurant' => (bool)$restaurant, 'dish' => (bool)$dish]) . PHP_EOL;
    exit(3);
}

$marker = 'CODEXDM8_' . strtoupper(bin2hex(random_bytes(9)));
$batchMarker = 'CODEXDM8_' . strtoupper(bin2hex(random_bytes(9)));
echo json_encode(['dialect' => $dialect, 'status' => 'starting', 'submit_ids' => [$marker, $batchMarker]]) . PHP_EOL;
$service = new \app\api\service\DishQuestionnaire($storeId, (int)$restaurant['id']);
$base = [
    'restaurant_id' => (int)$restaurant['id'],
    'dishes_uuid' => (string)$dish['uuid'],
    'comment' => 'CODEX达梦兼容落库测试',
    'wish_dish_name' => '测试菜品',
];
$first = $service->submit($base + ['submit_id' => $marker, 'score' => 5, 'tag_codes' => [3, 5]]);
$repeat = $service->submit($base + ['submit_id' => $marker, 'score' => 5, 'tag_codes' => [3, 5]]);
if ($first['duplicated'] || !$repeat['duplicated'] || (int)$first['id'] !== (int)$repeat['id']) {
    throw new RuntimeException('Submit idempotency failed');
}
$row = \think\Db::name('dish_questionnaire')->where('submit_id', $marker)->find();
$tagCount = (int)\think\Db::name('dish_questionnaire_tag')->where('questionnaire_id', (int)$first['id'])->count();
if (!$row || (int)$row['id'] !== (int)$first['id'] || (int)$row['score'] !== 5 || $tagCount !== 2) {
    throw new RuntimeException('Submission and tags did not persist');
}

$batch = $service->batchSubmit([$base + [
    'submit_id' => $batchMarker,
    'score' => 3,
    'tag_codes' => [],
    'comment' => '',
    'wish_dish_name' => '',
]]);
$batchId = (int)$batch['results'][0]['id'];
if ($batch['submitted_count'] !== 1 || $batchId <= 0 || (int)\think\Db::name('dish_questionnaire_tag')->where('questionnaire_id', $batchId)->count() !== 0) {
    throw new RuntimeException('Score-only batch path did not persist correctly');
}

$logic = new \app\p\logic\DishQuestionnaire($storeId);
$filters = [
    'restaurant_id' => (int)$restaurant['id'],
    'date_start' => date('Y-m-d'),
    'date_end' => date('Y-m-d'),
    'dishes_uuid' => (string)$dish['uuid'],
    'page' => 1,
    'page_size' => 100,
];
$summary = $logic->lists($filters, [(string)$restaurant['id']]);
$detail = $logic->detail($filters, [(string)$restaurant['id']]);
$ids = array_map('intval', array_column($detail['rows'], 'id'));
if ($summary['total'] < 1 || !in_array((int)$first['id'], $ids, true) || !in_array($batchId, $ids, true)) {
    throw new RuntimeException('Management list/detail did not read the persisted submissions');
}

$beforeInvalid = (int)\think\Db::name('dish_questionnaire')->count();
try {
    $service->submit($base + ['submit_id' => 'CODEXDM8_' . strtoupper(bin2hex(random_bytes(9))), 'score' => 0, 'tag_codes' => [3]]);
    throw new RuntimeException('Invalid score was accepted');
} catch (\InvalidArgumentException $expected) {
    if ($expected->getMessage() !== '请选择1至5分') throw $expected;
}
if ($beforeInvalid !== (int)\think\Db::name('dish_questionnaire')->count()) {
    throw new RuntimeException('Invalid submission changed business data');
}

$apiMarker = 'CODEXDM8_' . strtoupper(bin2hex(random_bytes(9)));
$request = \think\Request::instance();
$request->post($base + [
    'type' => (string)$restaurant['id'],
    'submit_id' => $apiMarker,
    'score' => 4,
    'tag_codes' => [3],
]);
$response = (new \app\api\controller\DishQuestionnaire($request))->submit();
$responseData = $response->getData();
$apiRow = \think\Db::name('dish_questionnaire')->where('submit_id', $apiMarker)->find();
if (($responseData['code'] ?? -1) !== 0 || !$apiRow || (int)$apiRow['id'] !== (int)($responseData['data']['id'] ?? 0)) {
    throw new RuntimeException('Controller submit did not persist: ' . json_encode($responseData));
}

echo json_encode([
    'dialect' => $dialect,
    'status' => 'passed',
    'submit_ids' => [$marker, $batchMarker, $apiMarker],
    'row_ids' => [(int)$first['id'], $batchId, (int)$apiRow['id']],
    'idempotent' => true,
    'tag_rows' => $tagCount,
    'management_readback' => true,
    'invalid_submission_no_write' => true,
    'controller_submit_readback' => true,
], JSON_UNESCAPED_UNICODE) . PHP_EOL;
