<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
import type { KbxBarcodeEvent } from '@kbx/contracts'
import { isKbxBarcodeDuplicate, normalizeKbxBarcode } from './barcodeGuard'

const props = withDefaults(defineProps<{
  enabled?: boolean
  minLength?: number
  maxLength?: number
  interKeyTimeoutMs?: number
  duplicateDebounceMs?: number
  label?: string
}>(), {
  enabled: true,
  minLength: 3,
  maxLength: 256,
  interKeyTimeoutMs: 70,
  duplicateDebounceMs: 180,
  label: 'SCAN READY',
})

const emit = defineEmits<{
  scan: [KbxBarcodeEvent]
  duplicateIgnored: [KbxBarcodeEvent]
}>()

const buffer = ref('')
const lastKeyAt = ref(0)
const manualValue = ref('')
let lastSubmitted:KbxBarcodeEvent|null=null

function resetBuffer(){buffer.value='';lastKeyAt.value=0}
function isEditableTarget(target: EventTarget | null) {
  if (!(target instanceof HTMLElement)) return false
  if (target.dataset.kbxBarcodeCapture === 'true') return false
  return target.matches('input, textarea, select, [contenteditable="true"]')
}

function submit(value: string, source: KbxBarcodeEvent['source']) {
  if(!props.enabled)return
  const scan=normalizeKbxBarcode(value,source,props.minLength,props.maxLength)
  if(!scan)return
  if(isKbxBarcodeDuplicate(scan,lastSubmitted,props.duplicateDebounceMs)){
    emit('duplicateIgnored',scan)
    return
  }
  lastSubmitted=scan
  emit('scan', scan)
}

function onKeydown(event: KeyboardEvent) {
  if (!props.enabled || event.ctrlKey || event.altKey || event.metaKey || isEditableTarget(event.target)) return

  const now = performance.now()
  if (lastKeyAt.value && now - lastKeyAt.value > props.interKeyTimeoutMs) resetBuffer()
  lastKeyAt.value = now

  if (event.key === 'Escape') { resetBuffer(); return }
  if (event.key === 'Enter') {
    const value = buffer.value
    resetBuffer()
    if (value.length >= props.minLength) {
      event.preventDefault()
      submit(value, 'keyboard-wedge')
    }
    return
  }

  if (event.key.length === 1) {
    if(buffer.value.length>=props.maxLength){resetBuffer();return}
    buffer.value += event.key
  }
}

function submitManual() {
  submit(manualValue.value, 'manual')
  manualValue.value = ''
}
function submitCamera(value:string){submit(value,'camera')}
function reset(){resetBuffer();manualValue.value='';lastSubmitted=null}
function onVisibilityChange(){if(document.visibilityState!=='visible')resetBuffer()}
watch(()=>props.enabled,value=>{if(!value)resetBuffer()})

onMounted(() => {document.addEventListener('keydown', onKeydown, true);document.addEventListener('visibilitychange',onVisibilityChange)})
onBeforeUnmount(() => {document.removeEventListener('keydown', onKeydown, true);document.removeEventListener('visibilitychange',onVisibilityChange)})
defineExpose({submitCamera,reset})
</script>

<template>
  <section class="capture" :class="{ disabled: !enabled }" aria-label="바코드 입력" :data-enabled="enabled">
    <div class="scan-box" aria-live="polite">
      <strong>{{ enabled ? label : 'SCAN PAUSED' }}</strong>
      <small>스캐너 입력은 Enter 종결자를 기준으로 인식하며 매우 짧은 중복 신호는 한 번만 처리합니다.</small>
    </div>

    <details class="manual">
      <summary>바코드 직접 입력</summary>
      <div class="manual-row">
        <input
          v-model="manualValue"
          data-kbx-barcode-capture="true"
          inputmode="text"
          autocomplete="off"
          :maxlength="maxLength"
          :disabled="!enabled"
          aria-label="바코드 직접 입력"
          @keyup.enter="submitManual"
        >
        <button type="button" :disabled="!enabled || manualValue.trim().length < minLength" @click="submitManual">입력</button>
      </div>
    </details>
  </section>
</template>

<style scoped>
.capture{margin:var(--kbx-space-4) 0}.scan-box{min-height:var(--kbx-wms-scan-box-min-height);border:calc(var(--kbx-border-width) * 2) solid var(--kbx-color-border-strong);border-radius:var(--kbx-radius-lg);display:flex;flex-direction:column;justify-content:center;align-items:center;gap:var(--kbx-space-1);background:var(--kbx-color-surface-muted)}.scan-box strong{font-size:var(--kbx-font-xl);letter-spacing:.06em}.scan-box small{color:var(--kbx-color-text-muted);font-size:var(--kbx-font-xs);text-align:center;padding:0 var(--kbx-space-2)}.disabled{opacity:.6}.manual{margin-top:var(--kbx-space-2);font-size:var(--kbx-font-sm)}.manual-row{display:grid;grid-template-columns:1fr var(--kbx-wms-manual-button-width);gap:var(--kbx-space-2);margin-top:var(--kbx-space-2)}.manual-row input,.manual-row button{min-height:var(--kbx-control-touch);font:inherit}.manual-row input{border:var(--kbx-border-width) solid var(--kbx-color-border);border-radius:var(--kbx-radius-md);padding:0 var(--kbx-space-3)}.manual-row button{border:var(--kbx-border-width) solid var(--kbx-color-border-strong);background:var(--kbx-color-surface);border-radius:var(--kbx-radius-md);font-weight:600}
</style>
