/**
 * 后端实现工程契约。
 *
 * 将 Controller 边界、DTO/校验、事务、幂等、安全、审计与契约对齐
 * 纳入编码前工作包和验证/交付阻断口径。
 */
const BACKEND_KEYWORDS = /后端|接口|API|endpoint|controller|数据库|migration|DTO|请求参数|响应|分页|权限|租户|幂等|事务|并发|审计|spring|nestjs|express/i;
const LOW_RISK_KEYWORDS = /文案|README|注释|样式|css|错别字|拼写|测试数据|fixture/i;
const SIMPLE_READ_ONLY_KEYWORDS = /简单\s*(?:GET|查询|详情)|只读(?:查询|接口)?|GET\s+详情/i;
export function requiresBackendImplementationContract(intent, route, changedFiles = []) {
    const text = `${intent} ${changedFiles.join(" ")}`;
    if (LOW_RISK_KEYWORDS.test(text) && !BACKEND_KEYWORDS.test(text))
        return false;
    if (SIMPLE_READ_ONLY_KEYWORDS.test(text) && !/(?:权限|租户|敏感|支付|财务|审计)/i.test(text))
        return false;
    if (route === "artifact_generation" && /文档|规格|设计|openapi|产物/i.test(text))
        return false;
    const relevantRoute = !route || ["code_change", "artifact_generation", "operation", "multi_stage_plan"].includes(route);
    return relevantRoute && BACKEND_KEYWORDS.test(text);
}
export function createBackendImplementationWorkPackage(taskId, intent) {
    return {
        task_id: taskId,
        status: "required",
        applicability_reason_zh: `该任务涉及后端接口或数据行为，需先确认实现工程约束: ${intent}`,
        controller_contracts: [],
        dto_and_validation: [],
        transaction_and_consistency: [],
        security_and_audit: [],
        api_db_alignment: [],
        tests_and_evidence: [],
    };
}
function workPackageComplete(workPackage) {
    return !!workPackage
        && workPackage.controller_contracts.length > 0
        && workPackage.dto_and_validation.length > 0
        && workPackage.transaction_and_consistency.length > 0
        && workPackage.security_and_audit.length > 0
        && workPackage.api_db_alignment.length > 0
        && workPackage.tests_and_evidence.length > 0;
}
export function evaluateBackendImplementationGate(input) {
    if (!requiresBackendImplementationContract(input.intent, input.route, input.changed_files)) {
        return {
            applicable: false,
            allowed: true,
            status: "not_applicable",
            reason_zh: "非后端实现任务，不触发后端工程工作包",
        };
    }
    if (!workPackageComplete(input.work_package)) {
        return {
            applicable: true,
            allowed: false,
            status: "blocked",
            reason_zh: "后端实现任务缺少完整工程工作包，不得开始编码",
            work_package: input.work_package ?? createBackendImplementationWorkPackage(input.task_id, input.intent),
        };
    }
    return {
        applicable: true,
        allowed: true,
        status: "satisfied",
        reason_zh: "后端实现工程工作包已具备，可进入实现并在审查阶段复验",
        work_package: { ...input.work_package, status: "satisfied" },
    };
}
function finding(category, severity, file, evidence, suggestion_zh) {
    return { category, severity, file, evidence, suggestion_zh };
}
function isJavaEntityModel(file, content) {
    return /(?:^|\/)(?:entity|domain|model)\//i.test(file)
        || /\bclass\s+\w*(?:Entity|DO|PO)\b/i.test(content)
        || /@(?:Entity|Table)\b/.test(content);
}
function isJavaBoundaryDataModel(file, content) {
    return /(?:DTO|Dto|VO|Vo|Request|Response|Command|Query)\.java$/i.test(file)
        || /\bclass\s+\w*(?:DTO|Dto|VO|Vo|Request|Response|Command|Query)\b/i.test(content);
}
export function reviewBackendImplementationFiles(fileContents) {
    const findings = [];
    for (const [file, content] of Object.entries(fileContents)) {
        const lowered = file.toLowerCase();
        const controller = /controller|routes?|handler/.test(lowered);
        if (/\.java$/i.test(file)) {
            const javaEntity = isJavaEntityModel(file, content);
            const javaBoundaryModel = isJavaBoundaryDataModel(file, content);
            if (javaEntity && /@Data\b/.test(content)) {
                findings.push(finding("model_lombok_contract", "hard_fail", file, "持久化 Entity 使用 @Data，容易引入 equals/hashCode/toString 递归、懒加载泄漏和敏感字段日志风险", "Entity 必须使用 @Getter/@Setter；需要 equals/hashCode/toString 时显式按业务键设计并排除敏感和关联字段。"));
            }
            if (javaEntity && !/@Getter\b/.test(content) || javaEntity && !/@Setter\b/.test(content)) {
                findings.push(finding("model_lombok_contract", "hard_fail", file, "持久化 Entity 未同时声明 @Getter 与 @Setter", "Entity 保持薄数据载体，默认使用 @Getter/@Setter，不使用 @Data。"));
            }
            if (javaBoundaryModel && !/@Data\b/.test(content)) {
                findings.push(finding("model_lombok_contract", "hard_fail", file, "DTO/VO/Request/Response 边界对象未使用 @Data", "DTO、VO、Request、Response、Command、Query 等边界数据对象默认使用 @Data，保持字段访问、构造和序列化行为一致。"));
            }
        }
        if (controller && /(?:return|Promise<|ResponseEntity<)\s*[\w<, ?]*(?:Entity|DO|Po)\b|@RequestBody\s+\w*(?:Entity|DO|Po)\b/i.test(content)) {
            findings.push(finding("controller_boundary", "hard_fail", file, "接口边界直接暴露持久化实体", "使用请求/响应 DTO，并在应用服务或 mapper 中完成实体映射。"));
        }
        if (controller && /(?:@PostMapping|@PutMapping|@PatchMapping|router\.(?:post|put|patch))/.test(content)
            && !/(?:@Valid|@Validated|validate\(|zod|class-validator|Joi|RequestDto|Command|Input)/i.test(content)) {
            findings.push(finding("dto_validation", "hard_fail", file, "写接口缺少 DTO 或输入校验证据", "定义请求对象并执行字段、枚举和边界校验。"));
        }
        if (controller && /(?:page|Pageable|pagination|limit|size)/i.test(content)
            && !/(?:max|maxPageSize|Math\.min|@Max|size\s*<=|limit\s*<=)/i.test(content)) {
            findings.push(finding("pagination", "warning", file, "分页入口未体现上限限制", "限制 page size 并对白名单排序字段做校验。"));
        }
        if (/(?:payment|callback|webhook|createOrder|submit|缴费|支付)/i.test(`${file} ${content}`)
            && /(?:@PostMapping|router\.post|async\s+\w+\s*\()/i.test(content)
            && !/(?:Idempotency|idempot|requestId|request_id|unique|幂等)/i.test(content)) {
            findings.push(finding("idempotency", "hard_fail", file, "可重复提交的写入流程未声明幂等保护", "增加幂等键、唯一约束或重复请求结果复用策略。"));
        }
        if (/@Transactional[\s\S]{0,1000}(?:RestTemplate|WebClient|HttpClient|Feign|fetch\(|axios\.|send\(|publish\()/i.test(content)) {
            findings.push(finding("transaction", "hard_fail", file, "事务范围内包含外部调用或消息发送", "缩短事务边界，使用 outbox/补偿或事务提交后执行外部交互。"));
        }
        const writes = (content.match(/\.(?:save|insert|update|delete)\s*\(/gi) ?? []).length;
        if (/(?:service|usecase)/.test(lowered) && writes >= 2 && !/@Transactional/i.test(content)) {
            findings.push(finding("transaction", "hard_fail", file, "多次持久化写入未体现事务边界", "在应用服务定义事务边界并补充回滚一致性测试。"));
        }
        if (/(?:tenant|机构|organization|权限|role|account-status|折扣|财务|payment)/i.test(`${file} ${content}`)
            && controller && !/(?:tenantId|tenant_id|organizationId|@PreAuthorize|authorize|permission|audit|审计)/i.test(content)) {
            findings.push(finding("security_tenant", "hard_fail", file, "敏感业务接口缺少租户、授权或审计约束证据", "补充权限校验、租户隔离与关键操作审计。"));
        }
    }
    return findings;
}
export function hasBlockingBackendFindings(findings) {
    return findings.some((item) => item.severity === "hard_fail");
}
export function verifyBackendArtifactAlignment(input) {
    const findings = [];
    if (input.sourceFiles && Object.keys(input.sourceFiles).length > 0 && !input.openapiText) {
        findings.push(finding("api_db_alignment", "hard_fail", "docs/api/openapi.yaml", "后端接口实现变更缺少 OpenAPI 权威资产", "补齐或更新 OpenAPI，并复验 DTO 字段和错误语义。"));
    }
    if (input.apiDocumentText && !input.openapiText) {
        findings.push(finding("api_db_alignment", "hard_fail", "docs/api", "存在 API 规格文档但缺少 OpenAPI 权威资产", "补齐 OpenAPI 并对齐端点、字段、错误码与枚举。"));
    }
    if (input.apiDocumentText && !input.migrationText && /数据库|字段|表结构|DDL/i.test(input.apiDocumentText)) {
        findings.push(finding("api_db_alignment", "hard_fail", "db/migrations", "接口声明依赖数据库结构但缺少 migration 权威证据", "补齐可执行 migration 并复验接口/数据库一致性。"));
    }
    if (input.apiDocumentText && input.openapiText) {
        const markdownEndpoints = [...input.apiDocumentText.matchAll(/\b(?:GET|POST|PUT|PATCH|DELETE)\s+(\/[A-Za-z0-9_/{}/.-]+)/g)]
            .map((match) => match[1] ?? "");
        const missingEndpoints = markdownEndpoints.filter((endpoint) => !(input.openapiText ?? "").includes(endpoint));
        if (missingEndpoints.length > 0) {
            findings.push(finding("api_db_alignment", "hard_fail", "docs/api/openapi.yaml", `Markdown API 中的端点未进入 OpenAPI: ${missingEndpoints.join(", ")}`, "补齐 OpenAPI operation，并复验请求响应字段和错误码。"));
        }
    }
    if (input.openapiText && input.sourceFiles) {
        for (const [file, content] of Object.entries(input.sourceFiles)) {
            for (const block of content.matchAll(/(?:interface|class)\s+\w*(?:Response|Dto|DTO)\w*\s*\{([\s\S]*?)\}/g)) {
                const fields = [...(block[1] ?? "").matchAll(/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?:\?|:)/g)].map((match) => match[1] ?? "");
                const missingFields = fields.filter((field) => !(input.openapiText ?? "").includes(field));
                if (missingFields.length > 0) {
                    findings.push(finding("api_db_alignment", "hard_fail", file, `响应/DTO 字段未在 OpenAPI 中找到: ${missingFields.join(", ")}`, "同步更新 OpenAPI schema 与 Markdown 字段表后重新复验。"));
                }
            }
        }
    }
    return findings;
}
//# sourceMappingURL=backend_implementation_contract.js.map