import type { KbxHomeAttentionItem, KbxHomeAttentionQueue, KbxHomeLaunchItem, KbxNavigationResolvedEntry, KbxOperationRun, KbxRecentNavigation, KbxUserNotification, KbxWorkspaceTab } from '@kbx/contracts'

const sourceLabel:Record<KbxHomeLaunchItem['source'],string>={dirty:'미저장',pinned:'고정',open:'열림',favorite:'즐겨찾기',recent:'최근',priority:'권장'}

function routeInstanceLabel(path:string, canonicalPath:string){
  if(path===canonicalPath)return undefined
  try{
    const pathname=new URL(path,'https://kbx.local').pathname
    const canonical=new URL(canonicalPath,'https://kbx.local').pathname
    const parts=pathname.split('/').filter(Boolean)
    const tail=parts.at(-1)??''
    const actionSegments=new Set(['edit','view','detail','modify'])
    const suffix=pathname.startsWith(canonical.endsWith('/')?canonical:`${canonical}/`)?pathname.slice(canonical.length).replace(/^\//,''):(actionSegments.has(tail.toLocaleLowerCase())?(parts.at(-2)??tail):tail)
    if(!suffix)return '개별 업무'
    const value=decodeURIComponent(suffix).replace(/[\r\n\t]/g,' ').trim()
    return value.length>32?`${value.slice(0,29)}…`:value
  }catch{return '개별 업무'}
}

/**
 * Build one Home workbench without duplicating catalog-level entries.
 *
 * Open workspace instances are intentionally NOT deduplicated by ScreenId: two different order/detail
 * routes are two different pieces of work. Favorites/recents/priorities are then suppressed when that
 * screen already has an open instance, avoiding the old "same screen repeated in several card groups" problem.
 */
export function buildKbxHomeWorkbench(
  entries:KbxNavigationResolvedEntry[],
  favorites:KbxNavigationResolvedEntry[],
  recents:KbxRecentNavigation[],
  tabs:KbxWorkspaceTab[],
  limit=10,
):KbxHomeLaunchItem[]{
  const byId=new Map(entries.filter(entry=>entry.menuVisible!==false).map(entry=>[entry.screenId,entry]))
  const ordered:KbxHomeLaunchItem[]=[]
  const seenLaunchKeys=new Set<string>()
  const coveredScreenIds=new Set<string>()

  const addTab=(tab:KbxWorkspaceTab,source:'dirty'|'pinned'|'open')=>{
    const entry=byId.get(tab.screenId)
    if(!entry||seenLaunchKeys.has(tab.key))return
    seenLaunchKeys.add(tab.key)
    coveredScreenIds.add(entry.screenId)
    ordered.push({
      launchKey:tab.key,
      screenId:entry.screenId,
      title:entry.title,
      module:entry.module,
      section:entry.section,
      path:tab.path,
      source,
      sourceLabel:tab.resumed&&!tab.dirty?'복원':sourceLabel[source],
      tabKey:tab.key,
      instanceLabel:routeInstanceLabel(tab.path,entry.path),
      homeGroup:entry.homeGroup,
    })
  }
  const addCatalog=(entry:KbxNavigationResolvedEntry|undefined,source:'favorite'|'recent'|'priority',path?:string)=>{
    if(!entry||entry.menuVisible===false||coveredScreenIds.has(entry.screenId))return
    const launchKey=`screen:${entry.screenId}`
    if(seenLaunchKeys.has(launchKey))return
    seenLaunchKeys.add(launchKey)
    coveredScreenIds.add(entry.screenId)
    ordered.push({launchKey,screenId:entry.screenId,title:entry.title,module:entry.module,section:entry.section,path:path??entry.path,source,sourceLabel:sourceLabel[source],homeGroup:entry.homeGroup})
  }

  ;[...tabs].filter(tab=>tab.dirty).sort((a,b)=>b.lastActivatedAt.localeCompare(a.lastActivatedAt)).forEach(tab=>addTab(tab,'dirty'))
  ;[...tabs].filter(tab=>!tab.dirty).sort((a,b)=>(Number(Boolean(b.pinned))-Number(Boolean(a.pinned)))||b.lastActivatedAt.localeCompare(a.lastActivatedAt)).forEach(tab=>addTab(tab,tab.pinned?'pinned':'open'))
  favorites.forEach(entry=>addCatalog(entry,'favorite'))
  recents.forEach(recent=>addCatalog(byId.get(recent.screenId),'recent',recent.path))
  entries.filter(entry=>entry.homePriority!=null).sort((a,b)=>(a.homePriority??999)-(b.homePriority??999)||(a.order??999)-(b.order??999)).forEach(entry=>addCatalog(entry,'priority'))
  return ordered.slice(0,Math.max(1,limit))
}

/** Backward-compatible entry-only view for callers that do not need launch-source metadata. */
export function buildKbxHomeQuickStart(entries:KbxNavigationResolvedEntry[],favorites:KbxNavigationResolvedEntry[],recents:KbxRecentNavigation[],tabs:KbxWorkspaceTab[],limit=8){
  const byId=new Map(entries.map(entry=>[entry.screenId,entry]))
  return buildKbxHomeWorkbench(entries,favorites,recents,tabs,limit).map(item=>byId.get(item.screenId)).filter((entry):entry is KbxNavigationResolvedEntry=>Boolean(entry))
}


/**
 * Build the action-oriented Home attention queue.
 * Runtime entities are display inputs only; callers must revalidate any route before navigation.
 * Priority is business-defined, while items within one priority are newest-first for predictable recovery.
 */
export function buildKbxHomeAttentionQueue(
  entries:KbxNavigationResolvedEntry[],
  tabs:KbxWorkspaceTab[],
  operations:KbxOperationRun[],
  notifications:KbxUserNotification[],
  limit=8,
):KbxHomeAttentionQueue{
  const allowedIds=new Set(entries.filter(entry=>entry.menuVisible!==false).map(entry=>entry.screenId))
  const all:KbxHomeAttentionItem[]=[]
  for(const tab of tabs.filter(tab=>tab.dirty)){
    if(!allowedIds.has(tab.screenId))continue
    all.push({key:`dirty:${tab.key}`,source:'dirty',priority:10,occurredAt:tab.lastActivatedAt,title:tab.title,detail:'저장하지 않은 변경사항이 있습니다.',actionLabel:'계속 편집',screenId:tab.screenId,path:tab.path,tabKey:tab.key})
  }
  for(const operation of operations){
    if(operation.sourceScreenId&&!allowedIds.has(operation.sourceScreenId))continue
    const occurredAt=operation.completedAt??operation.startedAt??operation.requestedAt
    if(operation.status==='failed'||operation.status==='partially-completed')all.push({key:`operation:${operation.id}`,source:'operation-failed',priority:20,occurredAt,title:operation.title,detail:operation.resultMessage??(operation.status==='failed'?'작업이 실패했습니다.':'일부 항목이 처리되지 않았습니다.'),actionLabel:'작업 보기',screenId:operation.sourceScreenId,operationId:operation.id})
    else if(operation.status==='running'||operation.status==='queued')all.push({key:`operation:${operation.id}`,source:'operation-running',priority:40,occurredAt,title:operation.title,detail:operation.total?`${operation.processed??0} / ${operation.total} 처리`:'처리 중입니다.',actionLabel:'진행 보기',screenId:operation.sourceScreenId,operationId:operation.id})
  }
  for(const notification of notifications.filter(item=>!item.readAt)){
    if(notification.screenId&&!allowedIds.has(notification.screenId))continue
    const urgent=notification.severity==='warning'||notification.severity==='error'
    all.push({key:`notification:${notification.id}`,source:urgent?'notification-urgent':'notification',priority:urgent?30:50,occurredAt:notification.createdAt,title:notification.title,detail:notification.message,actionLabel:notification.action?.label??'알림 보기',screenId:notification.screenId,path:notification.action?.route,notificationId:notification.id})
  }
  all.sort((a,b)=>a.priority-b.priority||b.occurredAt.localeCompare(a.occurredAt)||a.key.localeCompare(b.key))
  const cap=Math.max(1,limit)
  const sourceCounts:KbxHomeAttentionQueue['sourceCounts']={}
  for(const item of all)sourceCounts[item.source]=(sourceCounts[item.source]??0)+1
  return {items:all.slice(0,cap),totalCount:all.length,overflowCount:Math.max(all.length-cap,0),sourceCounts}
}

/** Backward-compatible item-only view. Prefer buildKbxHomeAttentionQueue for exact counts/overflow. */
export function buildKbxHomeAttention(
  entries:KbxNavigationResolvedEntry[],
  tabs:KbxWorkspaceTab[],
  operations:KbxOperationRun[],
  notifications:KbxUserNotification[],
  limit=8,
):KbxHomeAttentionItem[]{
  return buildKbxHomeAttentionQueue(entries,tabs,operations,notifications,limit).items
}

