import fs from 'node:fs'
import path from 'node:path'

const root=process.cwd()
const read=p=>fs.readFileSync(path.join(root,p),'utf8')
const json=p=>JSON.parse(read(p))
const failures=[]
const check=(ok,message)=>{if(!ok)failures.push(message)}

const web=json('apps/web/package.json')
check(web.name==='@kbx/web','apps/web must be an explicit workspace package')
check(/^\^?8\./.test(web.devDependencies?.vite??''),'apps/web must target Vite 8')
check(String(web.scripts?.['dev:demo']??'').includes('--mode demo'),'demo runtime must require explicit Vite demo mode')
check(String(web.scripts?.build??'').includes('vue-tsc --noEmit'),'web build must typecheck before Vite build')
check(fs.existsSync(path.join(root,'apps/web/index.html')),'apps/web/index.html missing')
check(fs.existsSync(path.join(root,'apps/web/vite.config.ts')),'apps/web/vite.config.ts missing')
check(fs.existsSync(path.join(root,'apps/web/src/main.ts')),'apps/web/src/main.ts missing')
check(fs.existsSync(path.join(root,'apps/web/src/App.vue')),'apps/web/src/App.vue missing')
check(fs.existsSync(path.join(root,'apps/web/.env.demo')),'explicit .env.demo missing')

const main=read('apps/web/src/main.ts')
for(const token of ['createPinia','VueQueryPlugin','createRouter','PrimeVue','installKbx(app)','VITE_KBX_DEMO_MODE === \'true\'','installFrontendDemoApi']) check(main.includes(token),`main.ts runtime wiring missing: ${token}`)
const app=read('apps/web/src/App.vue')
check(app.includes("demoMode ? kbxPermissionCatalog.map(permission => permission.id) : []"),'production permissions must default to empty, not demo all-access')
check(app.includes("anonymous:secure-default"),'production preference scope must be secure-default')
const demo=read('apps/web/src/http/demo/installFrontendDemoApi.ts')
check(demo.includes('kbxHttp.defaults.adapter = demoAdapter'),'demo mode must replace only the HTTP transport boundary')
check(demo.includes('DEMO_OPERATION_UNSUPPORTED'),'unknown demo write/read paths must remain explicit, not silently succeed')
check(demo.includes("stage:'ready'")&&demo.includes("stage='await-location'")&&demo.includes("stage='await-item'"),'WMS demo must exercise explicit picking stage transitions')

const useOrders=read('apps/web/src/modules/oms/orders/search/useOrderSearch.ts')
for(const token of ['useRoute','hydrateSearchFromRoute','exceptionOnly === \'true\'','keyword.slice(0, 100)','channelId.slice(0, 64)']) check(useOrders.includes(token),`Home→Order context hardening missing: ${token}`)
check(useOrders.includes('const contextual = hydrateSearchFromRoute()')&&useOrders.includes('if (contextual) void executeSearch()'),'Home→Order context must still auto-execute after safe preference hydration')
const orderPage=read('apps/web/src/modules/oms/orders/search/OrderListPage.vue')
for(const token of ["id === 'excel.export'","id === 'excel.template'","id === 'excel.import'","id === 'excel.paste'","id === 'excel.history'",'전체 조회결과 Export API가 연결될 때까지 다운로드를 차단']) check(orderPage.includes(token),`OMS Excel completion guard missing: ${token}`)
check(!/\n\s+exportable\n/.test(orderPage),'T01 must not duplicate Excel output in both Command Bar and Grid toolbar')
const commandContract=read('packages/kbx-contracts/src/command.ts')
check(commandContract.includes("menu?: 'excel'"),'command contract missing standard Excel menu capability')
const commandBar=read('packages/kbx-ui/src/components/KbxCommandBar.vue')
check(commandBar.includes("command.menu==='excel'"),'KbxCommandBar must render standard Excel menu')
const excel=read('packages/kbx-ui/src/components/KbxExcelMenu.vue')
for(const token of ['role="menu"','role="menuitem"',"event.key === 'Escape'","event.key === 'ArrowDown'","event.key === 'ArrowUp'","event.key === 'Home'","event.key === 'End'",'onDocumentPointerDown','focusTrigger']) check(excel.includes(token),`KbxExcelMenu interaction contract missing: ${token}`)

const globalHeader=read('packages/kbx-ui/src/shell/KbxGlobalHeader.vue')
check(globalHeader.includes('@media(max-width:56rem)')&&globalHeader.includes('grid-template-columns:auto minmax(0,1fr) auto'),'Global Header must release the 220px navigation column under zoom/narrow pressure')
check(globalHeader.includes('@media(max-width:40rem)')&&globalHeader.includes('grid-template-columns:repeat(4,1fr)'),'Global Header actions must reflow instead of forcing horizontal overflow')
const sideNav=read('packages/kbx-ui/src/shell/KbxSideNavigation.vue')
check(sideNav.includes('.side-nav:not(.collapsed){width:var(--kbx-side-nav-collapsed-width)'),'Side Navigation must visually compact under 56rem/200% zoom pressure')
check(sideNav.includes('.side-nav:not(.collapsed) .module-block{display:none}'),'Expanded navigation detail must yield workspace width under narrow desktop pressure')

if(failures.length){console.error('FE runtime v42 validation failed:');for(const failure of failures)console.error(`- ${failure}`);process.exit(1)}
console.log('FE runtime v42 validation passed: runnable Vite shell, secure demo boundary, Home context, Excel menu contract.')
