import { isDeepEqual } from "remeda"
import type { ParsedKey } from "@opentui/core"

/**
 * Keybind info derived from OpenTUI's ParsedKey with our custom `leader` field.
 * This ensures type compatibility and catches missing fields at compile time.
 */
export type Info = Pick<ParsedKey, "name" | "ctrl" | "meta" | "shift" | "super"> & {
  leader: boolean // our custom field
}

export function match(a: Info | undefined, b: Info): boolean {
  if (!a) return false
  const normalizedA = { ...a, super: a.super ?? false }
  const normalizedB = { ...b, super: b.super ?? false }
  return isDeepEqual(normalizedA, normalizedB)
}

/**
 * Convert OpenTUI's ParsedKey to our Keybind.Info format.
 * This helper ensures all required fields are present and avoids manual object creation.
 */
export function fromParsedKey(key: ParsedKey, leader = false): Info {
  return {
    name: key.name === " " ? "space" : key.name,
    ctrl: key.ctrl,
    meta: key.meta,
    shift: key.shift,
    super: key.super ?? false,
    leader,
  }
}

export function toString(info: Info | undefined): string {
  if (!info) return ""
  const parts: string[] = []

  if (info.ctrl) parts.push("ctrl")
  if (info.meta) parts.push("alt")
  if (info.super) parts.push("super")
  if (info.shift) parts.push("shift")
  if (info.name) {
    if (info.name === "delete") parts.push("del")
    else parts.push(info.name)
  }

  let result = parts.join("+")

  if (info.leader) {
    result = result ? `<leader> ${result}` : `<leader>`
  }

  return result
}

export function parse(key: string): Info[] {
  if (key === "none") return []

  return key.split(",").map((combo) => {
    // Handle <leader> syntax by replacing with leader+
    const normalized = combo.replace(/<leader>/g, "leader+")
    const parts = normalized.toLowerCase().split("+")
    const info: Info = {
      ctrl: false,
      meta: false,
      shift: false,
      leader: false,
      name: "",
    }

    for (const part of parts) {
      switch (part) {
        case "ctrl":
          info.ctrl = true
          break
        case "alt":
        case "meta":
        case "option":
          info.meta = true
          break
        case "super":
          info.super = true
          break
        case "shift":
          info.shift = true
          break
        case "leader":
          info.leader = true
          break
        case "esc":
          info.name = "escape"
          break
        default:
          info.name = part
          break
      }
    }

    return info
  })
}
