import type { KbxShortcutDefinition, KbxShortcutScope } from '@kbx/contracts'

const scopeRank:Record<KbxShortcutScope,number>={application:1,page:2,grid:3,dialog:4,editor:5}
const protectedBrowserShortcuts=new Set(['F5','CTRL+L','CTRL+T','CTRL+W','CTRL+R'])
let nextId=1
const registrations=new Map<number,KbxShortcutDefinition[]>()
let listening=false

function normalizeConfiguredKey(value:string){return value.trim().replace(/\s+/g,'').toUpperCase()}
function eventKey(event:KeyboardEvent){
  const parts:string[]=[]
  if(event.ctrlKey||event.metaKey)parts.push('CTRL')
  if(event.altKey)parts.push('ALT')
  if(event.shiftKey)parts.push('SHIFT')
  const key=event.key===' '?'SPACE':event.key.toUpperCase()
  parts.push(key==='ESC'?'ESCAPE':key)
  return parts.join('+')
}
function isTextEditingTarget(target:EventTarget|null){
  const el=target instanceof HTMLElement?target:null
  if(!el)return false
  const tag=el.tagName.toLowerCase()
  return tag==='input'||tag==='textarea'||tag==='select'||el.isContentEditable
}
function candidates(event:KeyboardEvent){
  const key=eventKey(event)
  return [...registrations.values()].flat().filter(x=>normalizeConfiguredKey(x.key)===key&&x.enabled?.()!==false)
    .sort((a,b)=>(scopeRank[b.scope]-scopeRank[a.scope])||((b.priority??0)-(a.priority??0)))
}
function handle(event:KeyboardEvent){
  const key=eventKey(event)
  if(protectedBrowserShortcuts.has(key))return
  const matches=candidates(event)
  if(!matches.length)return
  const editing=isTextEditingTarget(event.target)
  const match=matches.find(x=>!editing||x.scope==='editor'||!['ENTER','SPACE','ARROWUP','ARROWDOWN','ARROWLEFT','ARROWRIGHT'].includes(key))
  if(!match)return
  event.preventDefault();void match.execute()
}
function ensureListener(){if(listening||typeof window==='undefined')return;window.addEventListener('keydown',handle);listening=true}
function releaseListener(){if(!listening||registrations.size||typeof window==='undefined')return;window.removeEventListener('keydown',handle);listening=false}

export function registerKbxShortcuts(shortcuts:KbxShortcutDefinition[]){
  for(const shortcut of shortcuts){
    const key=normalizeConfiguredKey(shortcut.key)
    if(protectedBrowserShortcuts.has(key))throw new Error(`KBX browser shortcut is protected: ${shortcut.key}`)
  }
  const id=nextId++;registrations.set(id,shortcuts);ensureListener()
  return ()=>{registrations.delete(id);releaseListener()}
}

export function getKbxShortcutDebugSnapshot(){return [...registrations.values()].flat().map(x=>({key:x.key,scope:x.scope,priority:x.priority??0}))}
