export type TipIntensity = 'off' | 'low' | 'standard'

export const DEFAULT_TIP_INTENSITY: TipIntensity = 'standard'

const TIP_INTENSITIES = new Set<TipIntensity>(['off', 'low', 'standard'])

export function normalizeTipIntensity(value: unknown): TipIntensity {
  const raw = String(value ?? '')
    .trim()
    .toLowerCase()
  if (TIP_INTENSITIES.has(raw as TipIntensity))
    return raw as TipIntensity
  return DEFAULT_TIP_INTENSITY
}

export type ShortcutId = 'commands' | 'timeline' | 'newSession'
export type ShortcutBindings = Readonly<Record<ShortcutId, string>>

export const DEFAULT_SHORTCUTS: ShortcutBindings = {
  commands: 'ctrl+p',
  timeline: 'mod+t',
  newSession: 'mod+n',
}

export type ShortcutMatchEvent = Readonly<{
  key?: string
  ctrlKey?: boolean
  metaKey?: boolean
  altKey?: boolean
  shiftKey?: boolean
}>

type ParsedShortcut = Readonly<{
  key: string
  mod: boolean
  ctrl: boolean
  meta: boolean
  alt: boolean
  shift: boolean
}>

function normalizeShortcutToken(token: string): string {
  switch (token) {
    case 'control':
      return 'ctrl'
    case 'command':
      return 'cmd'
    case 'option':
      return 'alt'
    default:
      return token
  }
}

export function isValidShortcutBinding(value: unknown): boolean {
  return Boolean(parseShortcutBinding(value))
}

function parseShortcutBinding(value: unknown): ParsedShortcut | null {
  const cleaned = String(value ?? '')
    .trim()
    .toLowerCase()
    .replace(/\s+/g, '')
  if (!cleaned)
    return null

  const rawTokens = cleaned
    .split('+')
    .map(normalizeShortcutToken)
    .filter(Boolean)
  if (rawTokens.length === 0)
    return null

  const key = rawTokens.pop() ?? ''
  if (!key)
    return null
  if (!/^(?:[a-z0-9]|f\d{1,2})$/.test(key))
    return null

  let mod = false
  let ctrl = false
  let meta = false
  let alt = false
  let shift = false

  for (const tok of rawTokens) {
    if (tok === 'mod') {
      mod = true
      continue
    }
    if (tok === 'ctrl') {
      ctrl = true
      continue
    }
    if (tok === 'cmd' || tok === 'meta') {
      meta = true
      continue
    }
    if (tok === 'alt') {
      alt = true
      continue
    }
    if (tok === 'shift') {
      shift = true
      continue
    }
    return null
  }

  return { key, mod, ctrl, meta, alt, shift }
}

function formatShortcutBinding(parsed: ParsedShortcut): string {
  const parts: string[] = []
  if (parsed.mod) {
    parts.push('mod')
  }
  else {
    if (parsed.ctrl)
      parts.push('ctrl')
    if (parsed.meta)
      parts.push('meta')
  }
  if (parsed.alt)
    parts.push('alt')
  if (parsed.shift)
    parts.push('shift')
  parts.push(parsed.key)
  return parts.join('+')
}

export function normalizeShortcutBinding(
  value: unknown,
  fallback: string,
): string {
  const parsed = parseShortcutBinding(value)
  if (!parsed)
    return fallback
  return formatShortcutBinding(parsed)
}

export function normalizeShortcutBindings(raw: unknown): ShortcutBindings {
  const input
    = raw && typeof raw === 'object' ? (raw as Record<string, unknown>) : {}
  const commands = normalizeShortcutBinding(
    input.commands,
    DEFAULT_SHORTCUTS.commands,
  )
  return {
    commands: commands === 'mod+p' ? 'ctrl+p' : commands,
    timeline: normalizeShortcutBinding(
      input.timeline,
      DEFAULT_SHORTCUTS.timeline,
    ),
    newSession: normalizeShortcutBinding(
      input.newSession,
      DEFAULT_SHORTCUTS.newSession,
    ),
  }
}

function isMacPlatform(): boolean {
  const proc = (globalThis as any)?.process
  const platform = typeof proc?.platform === 'string' ? proc.platform : ''
  if (platform)
    return platform === 'darwin'
  const nav = (globalThis as any)?.navigator
  const navPlatform = typeof nav?.platform === 'string' ? nav.platform : ''
  return /Mac|iPhone|iPad|iPod/i.test(navPlatform)
}

export function formatShortcutLabel(binding: string): string {
  const parsed = parseShortcutBinding(binding)
  if (!parsed)
    return ''
  const parts: string[] = []
  const isMac = isMacPlatform()

  if (parsed.mod) {
    parts.push(isMac ? 'Cmd' : 'Ctrl')
  }
  else {
    if (parsed.ctrl)
      parts.push('Ctrl')
    if (parsed.meta)
      parts.push(isMac ? 'Cmd' : 'Meta')
  }
  if (parsed.alt)
    parts.push(isMac ? 'Option' : 'Alt')
  if (parsed.shift)
    parts.push('Shift')

  const keyLabel
    = parsed.key.length === 1
      ? parsed.key.toUpperCase()
      : parsed.key.toUpperCase()
  parts.push(keyLabel)
  return parts.join('+')
}

export function matchShortcut(
  evt: ShortcutMatchEvent,
  binding: string,
): boolean {
  const parsed = parseShortcutBinding(binding)
  if (!parsed)
    return false
  const key = String(evt.key ?? '').toLowerCase()
  if (!key || key !== parsed.key)
    return false

  const hasCtrl = Boolean(evt.ctrlKey)
  const hasMeta = Boolean(evt.metaKey)
  const hasAlt = Boolean(evt.altKey)
  const hasShift = Boolean(evt.shiftKey)

  if (parsed.mod) {
    if (!hasCtrl && !hasMeta)
      return false
  }
  else {
    if (parsed.ctrl !== hasCtrl)
      return false
    if (parsed.meta !== hasMeta)
      return false
  }

  if (parsed.alt !== hasAlt)
    return false
  if (parsed.shift !== hasShift)
    return false

  return true
}
