import { AxiosError, type AxiosAdapter, type AxiosRequestConfig, type AxiosResponse } from 'axios'
import { kbxHttp } from '../http/kbxHttpClient'

const now = () => new Date().toISOString()
const clone = <T>(value: T): T => structuredClone(value)
const uid = () => crypto.randomUUID()

const customers = [
  { id:'11111111-1111-4111-8111-111111111111', code:'10001', displayName:'대한상사', secondaryText:'서울 · 정상', status:'active', metadata:{ businessNumber:'123-45-67890', representative:'김대표' } },
  { id:'22222222-2222-4222-8222-222222222222', code:'10002', displayName:'한빛유통', secondaryText:'경기 · 정상', status:'active', metadata:{ businessNumber:'234-56-78901', representative:'이대표' } },
  { id:'33333333-3333-4333-8333-333333333333', code:'10003', displayName:'새봄물류', secondaryText:'인천 · 정상', status:'active', metadata:{ businessNumber:'345-67-89012', representative:'박대표' } },
]
const warehouses = [
  { id:'aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa', code:'WH01', displayName:'서울물류센터', secondaryText:'수도권', status:'active' },
  { id:'bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb', code:'WH02', displayName:'인천물류센터', secondaryText:'수도권', status:'active' },
  { id:'cccccccc-cccc-4ccc-8ccc-cccccccccccc', code:'WH03', displayName:'부산물류센터', secondaryText:'영남권', status:'active' },
]

const items = [
  { id:'10000000-0000-4000-8000-000000000001', code:'ABC001', name:'운동화 BLACK 270', displayName:'운동화 BLACK 270', categoryName:'신발', specification:'BLACK / 270', unit:'EA', barcode:'8801234567001', defaultWarehouseId:warehouses[0].id, defaultWarehouseName:warehouses[0].displayName, lotManaged:false, expiryManaged:false, active:true, version:3 },
  { id:'10000000-0000-4000-8000-000000000002', code:'ABC002', name:'운동화 WHITE 265', displayName:'운동화 WHITE 265', categoryName:'신발', specification:'WHITE / 265', unit:'EA', barcode:'8801234567002', defaultWarehouseId:warehouses[0].id, defaultWarehouseName:warehouses[0].displayName, lotManaged:false, expiryManaged:false, active:true, version:2 },
  { id:'10000000-0000-4000-8000-000000000003', code:'DEF001', name:'기능성 양말', displayName:'기능성 양말', categoryName:'의류', specification:'FREE / BLACK', unit:'EA', barcode:'8801234567003', defaultWarehouseId:warehouses[1].id, defaultWarehouseName:warehouses[1].displayName, lotManaged:false, expiryManaged:false, active:true, version:5 },
  { id:'10000000-0000-4000-8000-000000000004', code:'FOOD01', name:'에너지바 40g', displayName:'에너지바 40g', categoryName:'식품', specification:'40g', unit:'EA', barcode:'8801234567004', defaultWarehouseId:warehouses[1].id, defaultWarehouseName:warehouses[1].displayName, lotManaged:true, expiryManaged:true, active:true, version:1 },
]

function demoOrderLifecycleFromShipment(value:string){
  return ({NEW:'DRAFT',READY:'CONFIRMED',CONFIRMED:'CONFIRMED',HOLD:'HOLD',SHIPPED:'SHIPPED',ERROR:'ERROR'} as Record<string,string>)[value] ?? value
}

const orderDetails = new Map<string, any>([
  ['20000000-0000-4000-8000-000000000001', {
    orderId:'20000000-0000-4000-8000-000000000001', orderNo:'ORD-260811-0001', version:4, status:'CONFIRMED', orderDate:'2026-08-11', customerId:customers[0].id, warehouseId:warehouses[0].id,
    receiverName:'홍길동', phone:'010-1234-5678', postalCode:'06236', address1:'서울특별시 강남구 테헤란로 1', address2:'101호',
    lines:[{id:'line-1',clientId:'line-1',itemId:items[0].id,itemCode:'ABC001',itemName:items[0].name,orderQty:2,unitPrice:89000,amount:178000,remark:''}],
  }],
  ['20000000-0000-4000-8000-000000000002', {
    orderId:'20000000-0000-4000-8000-000000000002', orderNo:'ORD-260811-0002', version:2, status:'DRAFT', orderDate:'2026-08-11', customerId:customers[1].id, warehouseId:warehouses[0].id,
    receiverName:'김하나', phone:'010-2345-6789', postalCode:'04524', address1:'서울특별시 중구 세종대로 10', address2:'',
    lines:[{id:'line-2',clientId:'line-2',itemId:items[2].id,itemCode:'DEF001',itemName:items[2].name,orderQty:5,unitPrice:12000,amount:60000,remark:'선물포장'}],
  }],
  ['20000000-0000-4000-8000-000000000003', {
    orderId:'20000000-0000-4000-8000-000000000003', orderNo:'ORD-260811-0003', version:6, status:'CONFIRMED', orderDate:'2026-08-11', customerId:customers[2].id, warehouseId:warehouses[1].id,
    receiverName:'박현장', phone:'010-3456-7890', postalCode:'22382', address1:'인천광역시 중구 공항동로 1', address2:'물류동',
    lines:[{id:'line-3',clientId:'line-3',itemId:items[1].id,itemCode:'ABC002',itemName:items[1].name,orderQty:1,unitPrice:92000,amount:92000,remark:''}],
  }],
])

let orderRows = [
  { id:'20000000-0000-4000-8000-000000000001', orderNo:'ORD-260811-0001', channelName:'쿠팡', orderedAt:'2026-08-11T09:15:00+09:00', customerName:'홍길동', itemSummary:'운동화 BLACK 270', totalQty:2, amount:178000, allocationStatus:'부족', shipmentStatus:'READY', exceptionCount:1 },
  { id:'20000000-0000-4000-8000-000000000002', orderNo:'ORD-260811-0002', channelName:'스마트스토어', orderedAt:'2026-08-11T09:38:00+09:00', customerName:'김하나', itemSummary:'기능성 양말', totalQty:5, amount:60000, allocationStatus:'정상', shipmentStatus:'NEW', exceptionCount:0 },
  { id:'20000000-0000-4000-8000-000000000003', orderNo:'ORD-260811-0003', channelName:'자사몰', orderedAt:'2026-08-11T10:02:00+09:00', customerName:'박현장', itemSummary:'운동화 WHITE 265', totalQty:1, amount:92000, allocationStatus:'정상', shipmentStatus:'READY', exceptionCount:0 },
  { id:'20000000-0000-4000-8000-000000000004', orderNo:'ORD-260811-0004', channelName:'쿠팡', orderedAt:'2026-08-11T10:17:00+09:00', customerName:'이소라', itemSummary:'에너지바 40g', totalQty:12, amount:36000, allocationStatus:'정상', shipmentStatus:'HOLD', exceptionCount:1 },
  { id:'20000000-0000-4000-8000-000000000005', orderNo:'ORD-260811-0005', channelName:'스마트스토어', orderedAt:'2026-08-11T11:05:00+09:00', customerName:'정우진', itemSummary:'기능성 양말 외 1종', totalQty:4, amount:84000, allocationStatus:'정상', shipmentStatus:'SHIPPED', exceptionCount:0 },
]

const auditByEntity = new Map<string, any[]>()
function audit(id:string, action:string, changes:any[] = []) {
  const list = auditByEntity.get(id) ?? []
  list.unshift({ id:uid(), occurredAt:now(), actor:{type:'user',displayName:'QA 사용자'}, action, changes })
  auditByEntity.set(id, list)
}
for (const id of orderDetails.keys()) audit(id, '주문 조회용 데모 데이터 생성')
for (const item of items) audit(item.id, '품목 기준정보 생성')

let notifications:any[] = [
  { id:'noti-1', severity:'warning', title:'재고부족 주문 7건', message:'출고 전 확인이 필요합니다.', createdAt:now(), screenId:'OMS-ORD-001', action:{id:'open',label:'주문 보기',route:'/oms/orders?exceptionOnly=true'} },
  { id:'noti-2', severity:'error', title:'OMS ↔ WMS 대사 불일치 3건', message:'원인 확인 후 재처리하세요.', createdAt:now(), screenId:'COMMON-REC-001', action:{id:'open',label:'대사 보기',route:'/operations/reconcile'} },
]
let operations:any[] = [
  { id:'job-1', type:'excel-import', title:'주문 Excel Import', sourceScreenId:'OMS-ORD-003', status:'running', requestedAt:now(), startedAt:now(), processed:13421, total:17894, succeeded:13218, failed:203, resultMessage:'75% 처리 중' },
]

const workItems:any[] = [
  { id:'op-1', sourceModule:'OMS', sourceType:'order', sourceId:orderRows[0].id, referenceNo:'ORD-260811-0001', sourceScreenId:'OMS-ORD-001', code:'STOCK_SHORTAGE', title:'주문 재고 부족', detail:'ABC001 가용재고 부족', severity:'warning', status:'open', ownerId:null, ownerName:null, occurredAt:'2026-08-11T09:15:00+09:00', dueAt:null, ageMinutes:75, version:1, context:{ itemCode:'ABC001' }, retryActionKey:null, allowManualResolution:true },
  { id:'op-2', sourceModule:'WMS', sourceType:'integration', sourceId:'sync-2', referenceNo:'SYNC-260811-0002', sourceScreenId:'COMMON-OPS-001', code:'SHIPMENT_SYNC', title:'출고 연계 지연', detail:'WMS 전송 재시도 대기', severity:'critical', status:'open', ownerId:null, ownerName:null, occurredAt:'2026-08-11T08:10:00+09:00', dueAt:null, ageMinutes:140, version:2, context:{ integration:'WMS' }, retryActionKey:'shipment-sync', allowManualResolution:false },
  { id:'op-3', sourceModule:'ERP', sourceType:'inventory', sourceId:'inventory-3', referenceNo:'INV-260811-0003', sourceScreenId:'ERP-INV-001', code:'INVENTORY_REVIEW', title:'재고 확인 필요', detail:'실사 차이 검토가 필요합니다.', severity:'info', status:'claimed', ownerId:'demo-user', ownerName:'QA 사용자', occurredAt:'2026-08-11T10:30:00+09:00', dueAt:null, ageMinutes:32, version:1, context:{}, retryActionKey:null, allowManualResolution:true },
]
function demoWorkItemActions(item:any){
  const actions:any[]=[{id:'navigate',label:'원 업무 보기',kind:'navigate'}]
  if(item.status==='open')actions.push({id:'claim',label:'내가 처리',kind:'claim',permission:'common.operations.claim'})
  if(['open','claimed'].includes(item.status)&&item.retryActionKey)actions.push({id:'retry',label:'재처리',kind:'retry',permission:'common.operations.retry'})
  if(['open','claimed'].includes(item.status)&&item.allowManualResolution)actions.push({id:'resolve',label:'해결 처리',kind:'resolve',permission:'common.operations.resolve'})
  return actions
}
const reconcileItems:any[] = [
  { id:'rec-1', reconcileType:'OMS_WMS_OUTBOUND_QTY', referenceNo:'ORD-260811-0001', sourceLabel:'OMS 주문수량', targetLabel:'WMS 피킹수량', expectedValue:'2', actualValue:'1', differenceValue:'-1', reasonCode:'PICK_SHORT', reasonText:'피킹부족', status:'mismatch', occurredAt:'2026-08-11T10:42:00+09:00', sourceId:orderRows[0].id, targetId:'pick-line-1', version:3 },
  { id:'rec-2', reconcileType:'OMS_WMS_OUTBOUND_QTY', referenceNo:'ORD-260811-0003', sourceLabel:'OMS 주문수량', targetLabel:'WMS 피킹수량', expectedValue:'1', actualValue:'1', differenceValue:'0', reasonCode:null, reasonText:null, status:'matched', occurredAt:'2026-08-11T10:38:00+09:00', sourceId:orderRows[2].id, targetId:'pick-line-3', version:1 },
  { id:'rec-3', reconcileType:'OMS_WMS_OUTBOUND_QTY', referenceNo:'ORD-260811-0004', sourceLabel:'OMS 주문수량', targetLabel:'WMS 피킹수량', expectedValue:'12', actualValue:'10', differenceValue:'-2', reasonCode:'SYNC_PENDING', reasonText:'연계 결과 안정화 대기', status:'pending', occurredAt:'2026-08-11T10:47:00+09:00', sourceId:orderRows[3].id, targetId:'pick-line-4', version:2 },
]


let claimRows:any[] = [
  {id:'50000000-0000-4000-8000-000000000001',claimNo:'CLM-260811-01',orderNo:'ORD-260811-0001',channelName:'쿠팡',type:'RETURN',reason:'사이즈 교환',requestedQty:1,status:'REQUESTED',ownerName:'QA 사용자',requestedAt:'2026-08-11T13:20:00+09:00',version:1},
  {id:'50000000-0000-4000-8000-000000000002',claimNo:'CLM-260811-02',orderNo:'ORD-260811-0003',channelName:'자사몰',type:'EXCHANGE',reason:'색상 교환',requestedQty:1,status:'APPROVED',ownerName:'QA 사용자',requestedAt:'2026-08-11T13:35:00+09:00',version:2},
  {id:'50000000-0000-4000-8000-000000000003',claimNo:'CLM-260811-03',orderNo:'ORD-260811-0004',channelName:'쿠팡',type:'CANCEL',reason:'고객 요청',requestedQty:2,status:'IN_PROGRESS',ownerName:'QA 사용자',requestedAt:'2026-08-11T14:10:00+09:00',version:3},
  {id:'50000000-0000-4000-8000-000000000004',claimNo:'CLM-260811-04',orderNo:'ORD-260811-0002',channelName:'스마트스토어',type:'RETURN',reason:'검수 필요',requestedQty:1,status:'HOLD',ownerName:'QA 사용자',requestedAt:'2026-08-11T14:30:00+09:00',version:2},
]

const pickingTask:any = {
  taskId:'30000000-0000-4000-8000-000000000001', taskNo:'PICK-260811-001', status:'ready', stage:'ready', version:1,
  currentLine:{ lineId:'pick-line-1', lineNo:23, locationCode:'A-03-02', itemId:items[0].id, itemCode:items[0].code, itemName:items[0].name, itemOption:items[0].specification, barcode:items[0].barcode, requiredQty:6, pickedQty:4, remainingQty:2 },
  completedLines:22, totalLines:138, completedQty:71, totalQty:427, message:'작업을 시작하세요.',
}

const imports = new Map<string, any>()

function ok(config: AxiosRequestConfig, data: unknown, status = 200): AxiosResponse {
  return { data, status, statusText: status === 204 ? 'No Content' : 'OK', headers:{}, config:config as any, request:{} }
}
function fail(config:AxiosRequestConfig,data:unknown,status:number):never {
  const response=ok(config,data,status)
  throw new AxiosError(typeof data==='object'&&data&&'title' in data?String((data as any).title):`Demo HTTP ${status}`,AxiosError.ERR_BAD_REQUEST,config as any,{},response)
}
function text(v:unknown){ return String(v ?? '').trim().toLowerCase() }
function body(config:AxiosRequestConfig):any {
  if (typeof config.data === 'string') { try { return JSON.parse(config.data) } catch { return config.data } }
  return config.data ?? {}
}
function params(config:AxiosRequestConfig):Record<string,any>{ return (config.params ?? {}) as Record<string,any> }
function path(config:AxiosRequestConfig){ return String(config.url ?? '').split('?')[0] }
function findLookup(list:any[], codeOrId:string){ return list.find(x=>x.id===codeOrId||x.code.toLowerCase()===codeOrId.toLowerCase()) ?? null }
function lookupResponse(list:any[], q:any){
  const keyword=text(q.query)
  const filtered=keyword?list.filter(x=>`${x.code} ${x.displayName} ${x.secondaryText??''}`.toLowerCase().includes(keyword)):list
  return { items:clone(filtered.slice(0,Number(q.pageSize??20))), totalCount:filtered.length }
}

const demoAdapter:AxiosAdapter = async config => {
  await new Promise(resolve => setTimeout(resolve, 90))
  const method=String(config.method??'get').toUpperCase(); const url=path(config); const q=params(config); const data=body(config)

  if(method==='GET'&&url==='/api/kbx/runtime/notice') return ok(config,null)
  if(method==='GET'&&url==='/api/kbx/runtime/operations') return ok(config,clone(operations))
  if(method==='GET'&&url==='/api/kbx/runtime/notifications') return ok(config,clone(notifications))
  if(method==='POST'&&/^\/api\/kbx\/runtime\/notifications\/[^/]+\/read$/.test(url)){const id=url.split('/').at(-2)!;const n=notifications.find(x=>x.id===id);if(n)n.readAt=now();return ok(config,undefined,204)}
  if(method==='POST'&&url==='/api/kbx/ux/events') return ok(config,undefined,204)
  if(method==='POST'&&url==='/api/common/suggestions') return ok(config,{id:uid(),receivedAt:now()})
  if(method==='POST'&&url==='/api/common/ai/ask') return ok(config,{answer:'현재 화면의 예외와 선택 상태를 기준으로 확인할 항목을 정리했습니다.',actions:[]})

  if(method==='GET'&&url==='/api/oms/orders'){
    let rows=[...orderRows]; const keyword=text(q.keyword)
    if(q.status) rows=rows.filter(x=>x.shipmentStatus===q.status)
    if(String(q.exceptionOnly)==='true'||q.exceptionOnly===true) rows=rows.filter(x=>x.exceptionCount>0)
    if(keyword) rows=rows.filter(x=>`${x.orderNo} ${x.customerName} ${x.itemSummary} ${x.channelName}`.toLowerCase().includes(keyword))
    const counters={all:orderRows.length,new:orderRows.filter(x=>x.shipmentStatus==='NEW').length,readyToShip:orderRows.filter(x=>x.shipmentStatus==='READY').length,exceptions:orderRows.filter(x=>x.exceptionCount>0).length}
    const pageSize=Number(q.pageSize??100); const page=Math.max(Number(q.page??1),1); const slice=rows.slice((page-1)*pageSize,page*pageSize)
    return ok(config,{items:clone(slice),totalCount:rows.length,totalQty:rows.reduce((s,x)=>s+x.totalQty,0),totalAmount:rows.reduce((s,x)=>s+x.amount,0),counters})
  }
  if(method==='GET'&&/^\/api\/oms\/orders\/[^/]+$/.test(url)){const id=url.split('/').at(-1)!;const existing=orderDetails.get(id);if(existing)return ok(config,clone(existing));const row=orderRows.find(x=>x.id===id);if(row)return ok(config,{orderId:id,orderNo:row.orderNo,version:1,status:demoOrderLifecycleFromShipment(row.shipmentStatus),orderDate:'2026-08-11',customerId:customers[0].id,warehouseId:warehouses[0].id,receiverName:row.customerName,phone:'010-0000-0000',address1:'서울특별시',lines:[]});return ok(config,null)}
  if(method==='GET'&&/^\/api\/oms\/orders\/[^/]+\/audit$/.test(url)){const id=url.split('/').at(-2)!;return ok(config,clone(auditByEntity.get(id)??[]))}
  if(method==='POST'&&url==='/api/oms/orders/ship'){
    const ids:Array<string>=data.mode==='ids'?(data.ids??[]):orderRows.filter(row=>row.shipmentStatus==='READY').map(row=>row.id)
    let accepted=0; for(const id of ids){const row=orderRows.find(x=>x.id===id);if(row&&row.shipmentStatus==='READY'){row.shipmentStatus='CONFIRMED';accepted++}}
    return ok(config,{requested:ids.length,accepted,rejected:ids.length-accepted})
  }
  if(method==='POST'&&url==='/api/oms/orders/register'){
    const id=uid();const orderNo=`ORD-260811-${String(orderRows.length+1).padStart(4,'0')}`;const detail={...data,orderId:id,orderNo,version:1,status:'DRAFT',lines:(data.lines??[]).map((line:any,index:number)=>{const item=items.find(x=>x.id===line.itemId);return{id:`${id}-${index+1}`,clientId:line.clientId,itemId:line.itemId,itemCode:item?.code??'',itemName:item?.name??'',orderQty:Number(line.orderQty),unitPrice:Number(line.unitPrice),amount:Number(line.orderQty)*Number(line.unitPrice),remark:line.remark??''}})};orderDetails.set(id,detail);orderRows.unshift({id,orderNo,channelName:'직접주문',orderedAt:now(),customerName:data.receiverName,itemSummary:detail.lines[0]?.itemName??'상품 없음',totalQty:detail.lines.reduce((s:number,x:any)=>s+x.orderQty,0),amount:detail.lines.reduce((s:number,x:any)=>s+x.amount,0),allocationStatus:'미확인',shipmentStatus:'NEW',exceptionCount:0});audit(id,'주문 등록');return ok(config,{orderId:id,orderNo,version:1,status:'DRAFT'})
  }
  if(method==='PUT'&&/^\/api\/oms\/orders\/[^/]+$/.test(url)){const id=url.split('/').at(-1)!;const existing=orderDetails.get(id);const version=Number(existing?.version??0)+1;const next={...(existing??{}),...data,orderId:id,orderNo:existing?.orderNo??`ORD-${id.slice(0,8)}`,version,status:existing?.status??'DRAFT',lines:(data.lines??existing?.lines??[]).map((line:any,index:number)=>{const item=items.find(x=>x.id===line.itemId);return{...line,id:line.id??`${id}-${index+1}`,itemCode:item?.code??line.itemCode??'',itemName:item?.name??line.itemName??'',amount:Number(line.orderQty)*Number(line.unitPrice)}})};orderDetails.set(id,next);audit(id,'주문 수정');return ok(config,{orderId:id,orderNo:next.orderNo,version,status:next.status})}
  if(method==='POST'&&/^\/api\/oms\/orders\/[^/]+\/confirm$/.test(url)){const id=url.split('/').at(-2)!;const existing=orderDetails.get(id);if(!existing)return fail(config,{type:'not-found',code:'ORDER_NOT_FOUND',title:'주문을 찾을 수 없습니다.'},404);if(existing.status!=='DRAFT')return fail(config,{type:'business-rule',code:'ORDER_NOT_CONFIRMABLE',title:'주문을 확정할 수 없습니다.',detail:'작성 상태의 주문만 확정할 수 있습니다.'},409);existing.version=Number(existing.version)+1;existing.status='CONFIRMED';audit(id,'주문 확정');return ok(config,{orderId:id,orderNo:existing.orderNo,version:existing.version,status:'CONFIRMED'})}

  if(url.startsWith('/api/lookups/customers')){
    if(method==='GET'&&url==='/api/lookups/customers')return ok(config,lookupResponse(customers,q))
    const key=decodeURIComponent(url.split('/').at(-1)!);return ok(config,clone(findLookup(customers,key)))
  }
  if(url.startsWith('/api/lookups/warehouses')){
    if(method==='GET'&&url==='/api/lookups/warehouses')return ok(config,lookupResponse(warehouses,q))
    const key=decodeURIComponent(url.split('/').at(-1)!);return ok(config,clone(findLookup(warehouses,key)))
  }
  if(url.startsWith('/api/lookups/items')){
    const lookupItems=items.map(x=>({id:x.id,code:x.code,displayName:x.name,secondaryText:`${x.specification} · ${x.unit}`,status:x.active?'active':'disabled',metadata:{availableQty:x.code==='ABC001'?8:120}}))
    if(method==='GET'&&url==='/api/lookups/items')return ok(config,lookupResponse(lookupItems,q))
    const key=decodeURIComponent(url.split('/').at(-1)!);return ok(config,clone(findLookup(lookupItems,key)))
  }

  if(method==='GET'&&url==='/api/erp/items'){const keyword=text(q.keyword);const found=keyword?items.filter(x=>`${x.code} ${x.name}`.toLowerCase().includes(keyword)):items;return ok(config,{items:clone(found),totalCount:found.length})}
  if(method==='GET'&&/^\/api\/erp\/items\/[^/]+$/.test(url)){const id=url.split('/').at(-1)!;return ok(config,clone(items.find(x=>x.id===id)??null))}
  if(method==='GET'&&/^\/api\/erp\/items\/[^/]+\/audit$/.test(url)){const id=url.split('/').at(-2)!;return ok(config,clone(auditByEntity.get(id)??[]))}
  if(method==='POST'&&url==='/api/erp/items'){const id=uid();const created={id,version:1,active:true,defaultWarehouseName:warehouses.find(x=>x.id===data.defaultWarehouseId)?.displayName??'',...data};items.push(created);audit(id,'품목 등록');return ok(config,{id,version:1,status:'사용'})}
  if(method==='PUT'&&/^\/api\/erp\/items\/[^/]+$/.test(url)){const id=url.split('/').at(-1)!;const target=items.find(x=>x.id===id);if(target){Object.assign(target,data,{version:Number(target.version)+1,defaultWarehouseName:warehouses.find(x=>x.id===data.defaultWarehouseId)?.displayName??target.defaultWarehouseName});audit(id,'품목 수정');return ok(config,{id,version:target.version,status:target.active?'사용':'사용중지'})}return ok(config,{id,version:1,status:'사용'})}
  if(method==='POST'&&/^\/api\/erp\/items\/[^/]+\/deactivate$/.test(url)){const id=url.split('/').at(-2)!;const target=items.find(x=>x.id===id);if(target){target.active=false;target.version=Number(target.version)+1;audit(id,'품목 사용중지');return ok(config,{id,version:target.version,status:'사용중지'})}return ok(config,{id,version:1,status:'사용중지'})}

  if(method==='GET'&&url==='/api/erp/inventory'){
    const inv=items.map((x,index)=>({itemId:x.id,itemCode:x.code,itemName:x.name,specification:x.specification,unit:x.unit,totalQty:[1280,721,312,96][index]??0,availableQty:[830,650,290,80][index]??0,allocatedQty:[430,61,12,8][index]??0,holdQty:[20,10,10,8][index]??0}))
    const keyword=text(q.keyword);const found=keyword?inv.filter(x=>`${x.itemCode} ${x.itemName}`.toLowerCase().includes(keyword)):inv;return ok(config,{items:found,totalCount:found.length})
  }
  if(method==='GET'&&/^\/api\/erp\/inventory\/[^/]+\/locations$/.test(url)){return ok(config,{items:[{warehouseCode:'WH01',warehouseName:'서울물류센터',locationCode:'A-01-01',onHandQty:300,availableQty:260},{warehouseCode:'WH01',warehouseName:'서울물류센터',locationCode:'A-01-02',onHandQty:530,availableQty:500}]})}
  if(method==='GET'&&/^\/api\/erp\/inventory\/[^/]+\/history$/.test(url)){return ok(config,{items:[{occurredAt:'2026-08-11T10:21:00+09:00',businessType:'출고',inQty:0,outQty:2,balanceQty:830,referenceNo:'ORD-260811-0001'},{occurredAt:'2026-08-11T08:40:00+09:00',businessType:'입고',inQty:100,outQty:0,balanceQty:832,referenceNo:'GR-260811-001'}]})}
  if(method==='POST'&&url==='/api/erp/item-prices/bulk'){return ok(config,{requested:data.rows?.length??0,saved:data.rows?.length??0,created:data.rows?.length??0,updated:0})}

  if(method==='GET'&&url==='/api/operations/work-items'){
    let rows=[...workItems];const keyword=text(q.keyword)
    if(q.module)rows=rows.filter(x=>x.sourceModule===q.module)
    if(q.severity)rows=rows.filter(x=>x.severity===q.severity)
    if(q.status)rows=rows.filter(x=>x.status===q.status)
    if(q.code)rows=rows.filter(x=>x.code===q.code)
    if(q.owner==='mine')rows=rows.filter(x=>x.ownerId==='demo-user')
    if(q.owner==='unassigned')rows=rows.filter(x=>!x.ownerId)
    if(keyword)rows=rows.filter(x=>`${x.title} ${x.detail??''} ${x.referenceNo} ${x.sourceId}`.toLowerCase().includes(keyword))
    const counters=Object.values(workItems.filter(x=>['open','claimed'].includes(x.status)).reduce((acc:any,item:any)=>{const current=acc[item.code]??{key:item.code,label:item.title,count:0,severity:item.severity};current.count++;if(item.severity==='critical')current.severity='critical';else if(item.severity==='warning'&&current.severity!=='critical')current.severity='warning';acc[item.code]=current;return acc},{}))
    return ok(config,{items:clone(rows.map(x=>({...x,actions:demoWorkItemActions(x)}))),totalCount:rows.length,counters:clone(counters)})
  }
  if(method==='POST'&&url==='/api/operations/work-items/claim'){let claimedCount=0;for(const id of data.ids??[]){const item=workItems.find(x=>x.id===id);if(item&&item.status==='open'){item.status='claimed';item.ownerId='demo-user';item.ownerName='QA 사용자';item.version++;claimedCount++}}return ok(config,{claimedCount,skippedCount:Math.max((data.ids??[]).length-claimedCount,0)})}
  if(method==='POST'&&url==='/api/operations/work-items/resolve'){let resolvedCount=0;for(const id of data.ids??[]){const item=workItems.find(x=>x.id===id);if(item&&['open','claimed'].includes(item.status)){item.status='resolved';item.version++;resolvedCount++}}return ok(config,{resolvedCount,rejectedCount:Math.max((data.ids??[]).length-resolvedCount,0)})}
  if(method==='POST'&&/^\/api\/operations\/work-items\/[^/]+\/retry$/.test(url))return ok(config,{accepted:true})
  if(method==='GET'&&url==='/api/reconcile/items'){
    const keyword=text(q.keyword);let rows=[...reconcileItems]
    if(q.reconcileType)rows=rows.filter(x=>x.reconcileType===q.reconcileType)
    if(q.status)rows=rows.filter(x=>x.status===q.status)
    if(keyword)rows=rows.filter(x=>`${x.referenceNo} ${x.reasonText??''}`.toLowerCase().includes(keyword))
    const summaryBase=reconcileItems.filter(x=>(!q.reconcileType||x.reconcileType===q.reconcileType)&&(!keyword||`${x.referenceNo} ${x.reasonText??''}`.toLowerCase().includes(keyword)))
    const summary={totalCount:summaryBase.length,matchedCount:summaryBase.filter(x=>x.status==='matched').length,mismatchCount:summaryBase.filter(x=>x.status==='mismatch').length,pendingCount:summaryBase.filter(x=>x.status==='pending').length,resolvedCount:summaryBase.filter(x=>x.status==='resolved').length}
    return ok(config,{items:clone(rows),summary})
  }
  if(method==='POST'&&url==='/api/reconcile/items/create-exceptions'){
    const requested=[...new Set(data.ids??[])].slice(0,500);let createdOrUpdatedCount=0
    for(const id of requested){const row=reconcileItems.find(x=>x.id===id);if(!row||!['mismatch','pending'].includes(row.status))continue;createdOrUpdatedCount++;const workId=`reconcile-${row.id}`;if(!workItems.some(x=>x.id===workId))workItems.push({id:workId,sourceModule:'COMMON',sourceType:'reconcile',sourceId:row.id,referenceNo:row.referenceNo,sourceScreenId:'COMMON-REC-001',code:'RECONCILE_MISMATCH',title:`대사 불일치 · ${row.referenceNo}`,detail:row.reasonText??'대사 근거 확인 필요',severity:'warning',status:'open',ownerId:null,ownerName:null,occurredAt:row.occurredAt,dueAt:null,ageMinutes:0,version:row.version,context:{reconcileType:row.reconcileType,expectedValue:row.expectedValue,actualValue:row.actualValue,differenceValue:row.differenceValue},retryActionKey:null,allowManualResolution:true})}
    return ok(config,{createdOrUpdatedCount,skippedCount:requested.length-createdOrUpdatedCount})
  }

  if(method==='GET'&&url==='/api/oms/claims'){
    let rows=[...claimRows];const keyword=text(q.keyword)
    if(q.type)rows=rows.filter(x=>x.type===q.type)
    if(q.status)rows=rows.filter(x=>x.status===q.status)
    if(keyword)rows=rows.filter(x=>`${x.claimNo} ${x.orderNo} ${x.reason} ${x.channelName}`.toLowerCase().includes(keyword))
    return ok(config,{items:clone(rows),totalCount:rows.length})
  }
  if(method==='POST'&&/^\/api\/oms\/claims\/[^/]+\/(approve|hold|start|complete)$/.test(url)){
    const transition=url.split('/').at(-1)!;const id=url.split('/').at(-2)!;const row=claimRows.find(x=>x.id===id)
    const policy:any={approve:{from:'REQUESTED',to:'APPROVED'},hold:{from:'REQUESTED',to:'HOLD'},start:{from:'APPROVED',to:'IN_PROGRESS'},complete:{from:'IN_PROGRESS',to:'COMPLETED'}}
    const rule=policy[transition]
    if(row&&rule&&row.status===rule.from){row.status=rule.to;row.version++;return ok(config,{id:row.id,status:row.status,version:row.version})}
    return fail(config,{type:'business-rule',code:'CLAIM_TRANSITION_NOT_ALLOWED',title:'현재 상태에서는 요청한 클레임 전이를 실행할 수 없습니다.',detail:`${rule?.from??'허용 상태'} 상태를 확인하세요.`},409)
  }

  if(method==='GET'&&/^\/api\/wms\/picking\/tasks\/[^/]+$/.test(url))return ok(config,clone(pickingTask))
  if(method==='POST'&&/^\/api\/wms\/picking\/tasks\/[^/]+\/start$/.test(url)){pickingTask.status='picking';pickingTask.stage='await-location';pickingTask.message='A-03-02 위치를 스캔하세요.';pickingTask.version++;return ok(config,clone(pickingTask))}
  if(method==='POST'&&/^\/api\/wms\/picking\/tasks\/[^/]+\/scan$/.test(url)){
    const raw=String(data.normalizedValue??data.rawValue??data.barcode??'')
    if(pickingTask.stage==='await-location'){
      const accepted=raw===pickingTask.currentLine?.locationCode
      if(accepted){pickingTask.stage='await-item';pickingTask.message='상품을 스캔하세요.';pickingTask.version++}
      return ok(config,{accepted,duplicate:false,task:clone(pickingTask),feedback:accepted?'success':'error',message:accepted?'위치를 확인했습니다.':`잘못된 위치입니다. ${pickingTask.currentLine?.locationCode}로 이동하세요.`})
    }
    const expected=pickingTask.currentLine?.barcode
    if(raw===expected&&pickingTask.currentLine){pickingTask.currentLine.pickedQty++;pickingTask.currentLine.remainingQty=Math.max(pickingTask.currentLine.requiredQty-pickingTask.currentLine.pickedQty,0);pickingTask.completedQty++;pickingTask.version++;pickingTask.message=pickingTask.currentLine.remainingQty===0?'현재 상품 피킹을 완료했습니다.':'수량을 반영했습니다.';return ok(config,{accepted:true,duplicate:false,task:clone(pickingTask),feedback:'success',message:pickingTask.message})}
    return ok(config,{accepted:false,duplicate:false,task:clone(pickingTask),feedback:'error',message:'다른 상품입니다.'})
  }
  if(method==='POST'&&/^\/api\/wms\/picking\/tasks\/[^/]+\/quantity$/.test(url)){if(pickingTask.currentLine){const before=pickingTask.currentLine.pickedQty;pickingTask.currentLine.pickedQty=Number(data.pickedQty??0);pickingTask.currentLine.remainingQty=Math.max(pickingTask.currentLine.requiredQty-pickingTask.currentLine.pickedQty,0);pickingTask.completedQty+=pickingTask.currentLine.pickedQty-before;pickingTask.version++;pickingTask.message='피킹 수량을 변경했습니다.'}return ok(config,{accepted:true,duplicate:false,task:clone(pickingTask),feedback:'success',message:pickingTask.message})}
  if(method==='POST'&&/^\/api\/wms\/picking\/tasks\/[^/]+\/exceptions$/.test(url)){pickingTask.status='exception';pickingTask.version++;return ok(config,clone(pickingTask))}

  if(method==='POST'&&url==='/api/imports/sessions'){
    const id=uid();const mapping=[{sourceColumn:'주문번호',targetField:'orderNo',source:'exact',confidence:1,reason:'정확 일치'},{sourceColumn:'주문일자',targetField:'orderDate',source:'alias',confidence:1,reason:'Alias 일치'},{sourceColumn:'업체코드',targetField:'customerCode',source:'alias',confidence:1,reason:'Alias 일치'},{sourceColumn:'출고창고',targetField:'warehouseCode',source:'alias',confidence:1,reason:'Alias 일치'},{sourceColumn:'받는분',targetField:'receiverName',source:'alias',confidence:1,reason:'Alias 일치'},{sourceColumn:'상품코드',targetField:'itemCode',source:'alias',confidence:1,reason:'Alias 일치'},{sourceColumn:'수량',targetField:'orderQty',source:'alias',confidence:1,reason:'Alias 일치'}];const session={id,importType:'oms.orders.v1',screenId:'OMS-ORD-003',fileName:'demo-orders.xlsx',status:'mapping-required',totalRows:128,validRows:0,invalidRows:0,warningRows:0,createdRows:0,updatedRows:0,progressPercent:10,mapping,sourceColumns:mapping.map(x=>x.sourceColumn),createdAt:now()};imports.set(id,session);operations=[{id:`import:${id}`,type:'excel-import',title:'주문 Excel Import',sourceScreenId:'OMS-ORD-003',status:'running',requestedAt:now(),startedAt:now(),processed:0,total:128,succeeded:0,failed:0},...operations];return ok(config,clone(session))
  }
  if(method==='GET'&&/^\/api\/imports\/sessions\/[^/]+$/.test(url)){const id=url.split('/').at(-1)!;return ok(config,clone(imports.get(id)??null))}
  if(method==='PUT'&&/^\/api\/imports\/sessions\/[^/]+\/mapping$/.test(url)){const id=url.split('/').at(-2)!;const s=imports.get(id);if(s){s.mapping=data.mappings??[];s.status='uploaded';s.progressPercent=20}return ok(config,clone(s))}
  if(method==='POST'&&/^\/api\/imports\/sessions\/[^/]+\/validate$/.test(url)){const id=url.split('/').at(-2)!;const s=imports.get(id);if(s){Object.assign(s,{status:'validated',validRows:125,invalidRows:3,warningRows:2,progressPercent:60,errors:[{rowNumber:8,field:'itemCode',sourceColumn:'상품코드',code:'ITEM_NOT_FOUND',message:'존재하지 않는 품목코드입니다.',severity:'error'}]})}return ok(config,clone(s))}
  if(method==='POST'&&/^\/api\/imports\/sessions\/[^/]+\/commit$/.test(url)){const id=url.split('/').at(-2)!;const s=imports.get(id);if(s){Object.assign(s,{status:'partially-completed',createdRows:120,updatedRows:5,progressPercent:100,completedAt:now()});const op=operations.find(x=>x.id===`import:${id}`);if(op)Object.assign(op,{status:'partially-completed',processed:128,succeeded:125,failed:3,completedAt:now(),resultMessage:'125건 반영 / 3건 오류'})}return ok(config,clone(s))}
  if(method==='POST'&&/^\/api\/imports\/sessions\/[^/]+\/saved-mappings$/.test(url))return ok(config,undefined,204)
  if(method==='GET'&&/^\/api\/imports\/oms.orders.v1\/template$/.test(url))return ok(config,new Blob(['KBX demo workbook'],{type:'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'}))
  if(method==='GET'&&/^\/api\/imports\/sessions\/[^/]+\/errors.xlsx$/.test(url))return ok(config,new Blob(['KBX demo errors'],{type:'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'}))

  if(method==='GET'&&url==='/api/kbx/external-data/status')return ok(config,{items:[{datasetId:'krx.daily',name:'KRX 일별 시세',provider:'KRX OPEN API',status:'healthy',lastSucceededAt:now(),freshness:{observedAt:now(),source:'KRX'}},{datasetId:'dart.corp',name:'DART 기업정보',provider:'OPENDART',status:'healthy',lastSucceededAt:now(),freshness:{observedAt:now(),source:'DART'}}]})
  if(method==='POST'&&/^\/api\/kbx\/external-data\/[^/]+\/refresh$/.test(url))return ok(config,{accepted:true})
  if(method==='GET'&&url==='/api/kbx/ux/metrics')return ok(config,{summary:{taskCompletionRate:0.96,manualInterventionRate:0.0318,validationFailureRate:0.012},screens:[]})
  if(method==='GET'&&url==='/api/kbx/experiments')return ok(config,{items:[]})
  if(method==='GET'&&url==='/api/kbx/experiments/assignments')return ok(config,{assignments:[]})

  // Frontend demo mode never fabricates a successful write for an unknown operation.
  // Returning a visible unsupported response makes missing FE/API coverage explicit during QA.
  console.warn(`[KBX demo API] unsupported ${method} ${url}`)
  return ok(config,{ type:'system', code:'DEMO_OPERATION_UNSUPPORTED', title:'이 화면의 Demo API가 아직 준비되지 않았습니다.', detail:`${method} ${url}` },501)
}

export function installFrontendDemoApi() {
  kbxHttp.defaults.adapter = demoAdapter
}
