import type { KbxWmsScanCommand } from '@kbx/contracts'

const STORAGE_PREFIX = 'kbx:wms:safe-retry:v2:'
const LEGACY_STORAGE_KEY = 'kbx:wms:safe-retry:v1'
const ANONYMOUS_SCOPE = 'anonymous:secure-default'
const MAX_QUEUE_ITEMS = 32

export interface QueuedPickingScan {
  command: KbxWmsScanCommand
  queuedAt: string
}

function scopeHash(scope:string){
  // Storage keys must not expose tenant/user identifiers. This is partitioning, not cryptography.
  let hash=2166136261
  for(const ch of scope){hash^=ch.charCodeAt(0);hash=Math.imul(hash,16777619)}
  return (hash>>>0).toString(36)
}
function store(scope:string){
  // Authenticated tenant/user scope can safely survive reload/browser restart. Anonymous/default
  // contexts stay session-only so a shared PDA cannot replay another operator's queue later.
  return scope&&scope!==ANONYMOUS_SCOPE?localStorage:sessionStorage
}
function storageKey(scope:string){return `${STORAGE_PREFIX}${scopeHash(scope||ANONYMOUS_SCOPE)}`}
function retireLegacyQueue(){
  // v1 was an unscoped localStorage queue. Never replay it after the isolation upgrade.
  try { localStorage.removeItem(LEGACY_STORAGE_KEY) } catch { /* storage can be unavailable */ }
}
function validItem(item:unknown): item is QueuedPickingScan {
  if(!item||typeof item!=='object'||!('queuedAt' in item)||typeof item.queuedAt!=='string'||!('command' in item)||!item.command||typeof item.command!=='object')return false
  const command=item.command
  return 'idempotencyKey' in command&&typeof command.idempotencyKey==='string'&&'taskId' in command&&typeof command.taskId==='string'&&'barcode' in command&&typeof command.barcode==='string'
}

export function readPickingRetryQueue(scope=''): QueuedPickingScan[] {
  retireLegacyQueue()
  try {
    const parsed = JSON.parse(store(scope).getItem(storageKey(scope)) ?? '[]') as unknown
    if (!Array.isArray(parsed)) return []
    return parsed.filter(validItem).slice(-MAX_QUEUE_ITEMS)
  } catch {
    return []
  }
}

export function queuePickingScan(command: KbxWmsScanCommand, scope='') {
  retireLegacyQueue()
  // Safety-first queue: only unacknowledged commands are retained for replay.
  // UI stops accepting the next authoritative scan until the server confirms this one.
  const queue = readPickingRetryQueue(scope)
  if (!queue.some(x => x.command.idempotencyKey === command.idempotencyKey)) {
    queue.push({ command, queuedAt: new Date().toISOString() })
    store(scope).setItem(storageKey(scope), JSON.stringify(queue.slice(-MAX_QUEUE_ITEMS)))
  }
}

export function removePickingScan(idempotencyKey: string, scope='') {
  const next = readPickingRetryQueue(scope).filter(x => x.command.idempotencyKey !== idempotencyKey)
  store(scope).setItem(storageKey(scope), JSON.stringify(next))
}

export function clearPickingRetryQueue(scope='') {
  store(scope).removeItem(storageKey(scope))
  retireLegacyQueue()
}
