'use strict';
const assert = require('assert');
const fs = require('fs');
const path = require('path');
const vm = require('vm');
(async () => {
const root = path.join(__dirname, '..');
const appSource = fs.readFileSync(path.join(root, 'public', 'app.js'), 'utf8');
const html = fs.readFileSync(path.join(root, 'public', 'index.html'), 'utf8');
const styles = fs.readFileSync(path.join(root, 'public', 'style.css'), 'utf8');
const operations = fs.readFileSync(path.join(root, 'src', 'routes', 'operations.js'), 'utf8');
const accountsRoute = fs.readFileSync(path.join(root, 'src', 'routes', 'accounts.js'), 'utf8');
const runner = fs.readFileSync(path.join(root, 'src', 'workers', 'task_runner.js'), 'utf8');
const rechargeService = fs.readFileSync(path.join(root, 'src', 'services', 'recharge_task_service.js'), 'utf8');
assert.match(
html,
/runOpenAIGetAuth\(\)[\s\S]{0,200}runOpenAIQueryPlan\(\)[\s\S]{0,200}openRechargeModal\(\)/,
'查询套餐按钮应位于提取授权JSON右侧',
);
assert.match(html, /
ChatGPT<\/th>\s* | 是否已充值<\/th>\s* | 授权JSON<\/th>\s* | AC凭证<\/th>\s* | Cli_AC凭证<\/th>\s* | 账号套餐<\/th>/);
assert.match(html, /x-model="rechargeCredentialForm\.keyId"/);
assert.match(html, /type="password"[^>]*x-model="rechargeCredentialForm\.secret"/);
assert.match(styles, /input\[type="text"\],\s*input\[type="password"\],\s*input\[type="number"\]/,
'API Secret 密码框应与 Key ID 使用同一套输入框样式');
assert.match(html, /x-model="rechargeCardKeys"/);
assert.match(html, /完整 ChatGPT Session(结构化 JSON)/);
assert.match(operations, /taskType === 'card_pay_recharge' && !isLocalRequest\(req\)/);
assert.match(operations, /hasOwnProperty\.call\(params, 'confirmDuplicate'\)[\s\S]{0,100}params\.confirmDuplicate !== false/);
assert.match(runner, /latest\.chatgpt_session/);
assert.match(runner, /sessionText:\s*latest\.chatgpt_session/);
assert.match(runner, /confirmDuplicate:\s*false/);
assert.match(runner, /parseInt\(params && params\.threadCount, 10\) \|\| 2/,
'未指定充值并发时服务端应默认使用 2');
assert.match(runner, /Math\.min\(requestedRechargeConcurrency, 5\)/,
'卡付充值应限制为最多 5 路并发');
assert.match(runner, /const rechargeStartSpacingMs\s*=\s*1000/,
'卡付充值请求应相隔 1 秒发起');
assert.match(runner, /const rechargeQueryConcurrency\s*=\s*2/,
'卡付任务查询应与提交并发分离并限制为 2 路');
assert.match(html, /id="recharge-concurrency"[\s\S]{0,180}min="1" max="5"/,
'充值弹窗应提供 1 到 5 的独立并发设置');
assert.match(runner, /type:\s*'progress',\s*current:\s*0,\s*total:\s*accounts\.length/,
'充值开始时应立即推送 0/总数进度');
assert.match(runner, /onPrepared:[\s\S]{0,800}onConfirmed:[\s\S]{0,800}onPoll:/,
'充值应逐阶段推送预创建、确认和轮询进度');
assert.match(runner, /stagePrefix[\s\S]{0,300}开始处理/,
'每个账号应实时打印开始处理信息');
assert.match(runner, /maxRechargeAttempts\s*=\s*3/,
'单个账号充值最多应尝试三次');
assert.match(runner, /const rechargeOperationId\s*=\s*operationMap\.get\(emailKey\)[\s\S]{0,100}createRechargeOperationId\(email, cardKey, false\)/,
'每个账号应复用认领阶段生成的稳定充值操作号');
assert.match(runner, /operationId:\s*attemptOffset\s*>\s*0[\s\S]{0,180}rechargeOperationId/,
'只有远端任务明确失败后才应使用新的尝试幂等号');
assert.match(runner, /使用同一卡密重试/,
'重试进度应明确提示使用同一卡密');
assert.match(rechargeService, /error\s*&&\s*error\.retryable\s*===\s*true/,
'修改型充值请求的瞬时HTTP错误必须保留为待确认');
assert.match(runner, /rechargeNeedsManualConfirmation\(error, remoteTaskId\)/,
'最终失败状态必须结合远端任务号判断是否等待人工确认');
assert.match(operations, /message:\s*account\s*\?\s*\(account\.message/,
'充值结论应通过 SSE 同步到通用处理结论');
assert.match(runner, /publishRecharge\([\s\S]{0,180}'等待已确认'/,
'结果待确认时应转为等待人工确认状态');
assert.match(operations, /const nextStatus\s*=\s*remoteTaskId\s*\?\s*'充值中'\s*:\s*'充值失败'/,
'任务中断时已提交任务应保持充值中,未提交账号才标记失败');
assert.match(accountsRoute, /router\.put\('\/:email\/recharge-status'/,
'应提供本机人工修改充值状态接口');
assert.match(html, / |