/**
 * Plain-DOM widget for rendering ::query{...} results inside a ProseMirror
 * decoration. No Vue instance — just direct DOM manipulation.
 *
 * Lifecycle:
 * 1. Constructor: creates container div, shows loading skeleton
 * 2. Async query resolves: replaces skeleton with results or empty state
 * 3. Destroy: cleans up any pending work
 */
import type { GraphService } from "~/services/graph"

export interface QueryAttrs {
  type?: string
  tag?: string
  property?: string
  equals?: string
}

export interface QueryResult {
  blockId: string
  pagePath: string
  title: string
}

const EMPTY_MESSAGES: Record<
  string,
  { icon: string; title: string; description: string }
> = {
  TODO: {
    icon: "i-lucide-list-checks",
    title: "No TODO tasks",
    description: "Type TODO at the start of a line to create a task.",
  },
  DOING: {
    icon: "i-lucide-loader",
    title: "No in-progress tasks",
    description: "Use DOING to mark a task as in progress.",
  },
  DONE: {
    icon: "i-lucide-check-circle",
    title: "No completed tasks",
    description: "Completed tasks will appear here.",
  },
  LATER: {
    icon: "i-lucide-clock",
    title: "No deferred tasks",
    description: "Use LATER to mark tasks you'll come back to.",
  },
  NOW: {
    icon: "i-lucide-play",
    title: "No active tasks",
    description: "Use NOW to mark what you're currently working on.",
  },
  WAITING: {
    icon: "i-lucide-hourglass",
    title: "No waiting tasks",
    description: "Use WAITING for tasks blocked on someone else.",
  },
  CANCELLED: {
    icon: "i-lucide-x-circle",
    title: "No cancelled tasks",
    description: "Use CANCELLED to mark tasks that won't be done.",
  },
}

const FALLBACK_EMPTY = {
  icon: "i-lucide-search",
  title: "No results",
  description: "Try adjusting your query.",
}

export class QueryWidget {
  dom: HTMLElement
  private resultsContainer: HTMLElement
  private _destroyed = false

  constructor(
    private attrs: QueryAttrs,
    private graph: GraphService,
  ) {
    this.dom = document.createElement("span")
    this.dom.className = "md-query-widget"

    // Loading skeleton (mimics USkeleton's animate-pulse)
    this.resultsContainer = document.createElement("div")
    this.resultsContainer.className = "md-query-results"
    this.resultsContainer.innerHTML = `
      <div class="md-query-loading">
        <div class="md-query-loading-item" style="width: 75%"></div>
        <div class="md-query-loading-item" style="width: 50%"></div>
        <div class="md-query-loading-item" style="width: 60%"></div>
      </div>`
    this.dom.appendChild(this.resultsContainer)

    // Fire query asynchronously
    this.executeQuery().then((results) => {
      this.render(results)
    })
  }

  private async executeQuery(): Promise<QueryResult[]> {
    try {
      const { type, tag, property, equals } = this.attrs

      if (tag) {
        const incoming = await this.graph.getIncoming(tag)
        return incoming
          .filter((r) => r.via.type === "tagged")
          .map((r) => ({
            blockId: r.from.id,
            pagePath: r.from.path ?? "",
            title: r.from.title ?? "",
          }))
      }

      if (property) {
        const entities = await this.graph.queryByProperty(property, equals)
        return entities.map((e) => ({
          blockId: e.id,
          pagePath: e.path ?? "",
          title: e.title ?? "",
        }))
      }

      if (type) {
        const entities = await this.graph.queryByProperty("task-state", type)
        return entities.map((e) => ({
          blockId: e.id,
          pagePath: e.path ?? "",
          title: e.title ?? "",
        }))
      }

      return []
    } catch {
      return []
    }
  }

  private render(results: QueryResult[]) {
    if (this.isDestroyed()) return
    if (results.length > 0) {
      const list = document.createElement("div")
      list.className = "md-query-list"

      for (const r of results) {
        const item = document.createElement("a")
        item.className = "md-query-item"
        item.href = `/${r.pagePath}`
        item.setAttribute("data-block-id", r.blockId)
        item.textContent = r.title || "(empty block)"
        item.addEventListener("mousedown", (e) => {
          // Prevent ProseMirror from intercepting the click and focusing the block
          e.preventDefault()
          e.stopPropagation()
        })
        item.addEventListener("click", (e) => {
          e.preventDefault()
          e.stopPropagation()
          window.location.href = `/${r.pagePath}`
        })
        list.appendChild(item)
      }

      this.resultsContainer.innerHTML = ""
      this.resultsContainer.appendChild(list)
    } else {
      const msg = EMPTY_MESSAGES[this.attrs.type ?? ""] ?? FALLBACK_EMPTY
      this.resultsContainer.innerHTML = `
        <div class="md-query-empty">
          <span class="md-query-empty-icon ${msg.icon}"></span>
          <p class="md-query-empty-title">${msg.title}</p>
          <p class="md-query-empty-description">${msg.description}</p>
        </div>`
    }
  }

  destroy() {
    this._destroyed = true
  }

  private isDestroyed(): boolean {
    return this._destroyed || !this.dom.isConnected
  }
}
