import fs from 'node:fs'
import path from 'node:path'
const root=process.cwd();const failures=[]
const read=p=>fs.readFileSync(path.join(root,p),'utf8')
const must=(text,needles,scope)=>needles.forEach(needle=>{if(!text.includes(needle))failures.push(`${scope} missing ${needle}`)})

const lookupContract=read('packages/kbx-contracts/src/lookup.ts')
must(lookupContract,['KbxLookupColumnDefinition','metadata.${string}','columns?: KbxLookupColumnDefinition[]','pageSize?: number'],'lookup presentation contract')
const lookup=read('packages/kbx-ui/src/components/KbxLookup.vue')
must(lookup,['resolveSequence','조회 공급자가 구성되지 않았습니다.','선택 정보를 불러오지 못했습니다.','코드를 확인하지 못했습니다.',':columns="columns"',':page-size="pageSize"'],'lookup async guard')
const lookupDialog=read('packages/kbx-ui/src/components/KbxLookupDialog.vue')
must(lookupDialog,["import KbxDialog from './KbxDialog.vue'",'requestSequence','pageCount','조회하지 못했습니다.','조회된 항목이 없습니다.','aria-selected','scrollSelectedIntoView'],'lookup dialog maturity')
if(/primevue\//.test(lookupDialog))failures.push('KbxLookupDialog must compose KBX primitives instead of importing PrimeVue directly')

const excelContract=read('packages/kbx-contracts/src/excel.ts')
must(excelContract,['export interface KbxImportFailure','failure?: KbxImportFailure'],'import failure contract')
const importGuard=read('packages/kbx-ui/src/excel/importGuard.ts')
must(importGuard,['validateKbxImportMappings','duplicate-target','required-missing','validateKbxImportFileCandidate',"endsWith('.xlsx')"],'import guard')
const excel=read('packages/kbx-ui/src/components/KbxExcelImport.vue')
must(excel,['localMapping = ref<KbxImportMapping[] | null>(null)','watch(() => props.session?.id','mappingIssues','KbxConfirm','requestCommit','isFailed','isCancelled','isPartial','새 파일로 다시 시작'],'Excel import recovery/mapping maturity')

const operations=read('packages/kbx-contracts/src/operations.ts')
must(operations,["permissionMode?: 'hide' | 'disable'"],'exception permission UX contract')
const exceptionDrawer=read('packages/kbx-ui/src/components/KbxExceptionDetailDrawer.vue')
must(exceptionDrawer,['KbxPermissionHostKey','KbxDrawer','permissionMode===\'disable\'','이 작업을 실행할 권한이 없습니다.','data-kbx-component="exception-detail-drawer"'],'exception drawer hardening')

const aiContract=read('packages/kbx-contracts/src/ai.ts')
must(aiContract,['KbxAiProposalValidationState','validation?: KbxAiProposalValidation','KbxAiAnswerAction','requiredCapability?: KbxAiCapability','requiredPermission?: string'],'AI action/validation contract')
const assistant=read('packages/kbx-ui/src/components/KbxAiAssistant.vue')
must(assistant,['KbxPermissionHostKey','actionAllowed','proposalAllowed','lastSubmitted','다시 질문','currentScreenLabel','현재 사용자 권한 또는 AI 허용 범위를 벗어난'],'AI assistant guard/recovery')
if(assistant.includes('{{ context.screenId }}'))failures.push('AI assistant must not expose ScreenId as the default user-facing current-screen label')
const proposal=read('packages/kbx-ui/src/components/KbxProposalPanel.vue')
must(proposal,['KbxPermissionHostKey','permissionAllowed','validationAllowed','data-validation','서버에서 대상·권한·업무규칙','대상 {{proposal.targets.length.toLocaleString()}}건'],'AI proposal enforcement')
const appFrame=read('apps/web/src/shell/KbxAppFrame.vue')
must(appFrame,['utilityAiError','네트워크 상태를 확인한 후 다시 질문하세요.',':ai-error="utilityAiError"',':ai-current-screen-label="utilityScreen?.title"'],'AI shell error recovery')

const barcodeGuard=read('packages/kbx-ui/src/wms/barcodeGuard.ts')
must(barcodeGuard,['normalizeKbxBarcode','isKbxBarcodeDuplicate'],'barcode guard')
const barcode=read('packages/kbx-ui/src/wms/KbxBarcodeCapture.vue')
must(barcode,['maxLength?: number','duplicateDebounceMs?: number','duplicateIgnored','isKbxBarcodeDuplicate','defineExpose({submitCamera,reset})','visibilitychange'],'barcode capture hardening')

const home=read('packages/kbx-ui/src/shell/KbxHomePage.vue')
must(home,['regularOpenCount','open:regularOpenCount.value','watch(modules','visibleScreenCount','aria-live="polite"'],'Home navigation resilience')

const templateManifest=read('packages/kbx-ui/src/registry/templateManifest.ts')
const componentManifest=read('packages/kbx-ui/src/registry/componentManifest.ts')
const catalog=read('packages/kbx-ui/src/catalog/componentCatalog.ts')
const coreGroups=[...templateManifest.matchAll(/coreComponents:\[([^\]]+)\]/g)]
const coreComponents=new Set(coreGroups.flatMap(match=>[...match[1].matchAll(/'([^']+)'/g)].map(item=>item[1])))
const manifestNames=new Set([...componentManifest.matchAll(/name: '([^']+)'/g)].map(match=>match[1]))
const catalogNames=new Set([...catalog.matchAll(/component:'([^']+)'/g)].map(match=>match[1]))
for(const component of coreComponents){
  if(!manifestNames.has(component))failures.push(`template core component missing manifest: ${component}`)
  if(!catalogNames.has(component))failures.push(`template core component missing catalog scenarios: ${component}`)
}
for(const component of ['KbxLookupDialog','KbxValidationSummary','KbxExceptionSummary','KbxExceptionDetailDrawer','KbxRecordLifecycle','KbxBarcodeCapture','KbxNetworkIndicator','KbxWmsActionButton']){
  if(!catalogNames.has(component))failures.push(`v34 required catalog entry missing: ${component}`)
}
must(componentManifest,["KbxLookup', category: 'business', purpose: '비동기 race/error", "KbxLookupDialog', category: 'business', purpose: 'Provider 오류", "KbxExcelImport', category: 'business', purpose: '파일 preflight", "KbxExceptionDetailDrawer', category: 'business', purpose: '표준 Drawer", "KbxAiAssistant', category: 'business', purpose: 'Capability/Permission guard", "KbxBarcodeCapture', category: 'wms', purpose: 'Keyboard-wedge/Camera", "KbxHomePage', category: 'shell', purpose:"],'v34 component versions/descriptions')

if(failures.length){console.error(failures.join('\n'));process.exit(1)}
console.log(`v34 template/component/home validation passed: ${coreComponents.size} template core components have manifest+catalog coverage; Lookup/Import/Exception/AI/Barcode recovery and permission boundaries hardened; Home counts/filter recovery corrected.`)
