import { describe, expect, it } from "vitest"
import {
  contentHash,
  detectBlockType,
  extractLinks,
  extractTitle,
} from "./parse"

describe("contentHash", () => {
  it("returns a deterministic hash for the same content", () => {
    expect(contentHash("hello")).toBe(contentHash("hello"))
  })

  it("returns different hashes for different content", () => {
    expect(contentHash("hello")).not.toBe(contentHash("world"))
  })

  it("handles empty string", () => {
    expect(contentHash("")).toBe("0")
  })
})

describe("detectBlockType", () => {
  it("classifies heading", () => {
    expect(detectBlockType("# Title")).toBe("heading")
    expect(detectBlockType("## Subtitle")).toBe("heading")
    expect(detectBlockType("###### H6")).toBe("heading")
  })

  it("classifies task states", () => {
    expect(detectBlockType("TODO buy milk")).toBe("task")
    expect(detectBlockType("DOING implement feature")).toBe("task")
    expect(detectBlockType("DONE ship it")).toBe("task")
    expect(detectBlockType("LATER maybe")).toBe("task")
    expect(detectBlockType("NOW urgent")).toBe("task")
    expect(detectBlockType("WAITING on review")).toBe("task")
    expect(detectBlockType("CANCELLED wontfix")).toBe("task")
  })

  it("classifies callout", () => {
    expect(detectBlockType("> [!NOTE] info")).toBe("callout")
    expect(detectBlockType("> [!WARNING] caution")).toBe("callout")
  })

  it("classifies blockquote", () => {
    expect(detectBlockType("> quoted text")).toBe("blockquote")
  })

  it("classifies code fence", () => {
    expect(detectBlockType("```typescript")).toBe("code")
    expect(detectBlockType("```")).toBe("code")
  })

  it("classifies table", () => {
    expect(detectBlockType("| A | B |")).toBe("table")
  })

  it("classifies math block", () => {
    expect(detectBlockType("$$")).toBe("math")
    expect(detectBlockType("$$ E = mc^2 $$")).toBe("math")
  })

  it("classifies property", () => {
    expect(detectBlockType("author:: John")).toBe("property")
    expect(detectBlockType("date:: 2026-06-21")).toBe("property")
  })

  it("classifies plain text as paragraph", () => {
    expect(detectBlockType("some text")).toBe("paragraph")
    expect(detectBlockType("")).toBe("paragraph")
  })
})

describe("extractTitle", () => {
  it("extracts the first H1", () => {
    expect(extractTitle("# Hello\n\nSome text")).toBe("Hello")
  })

  it("returns empty string when no H1", () => {
    expect(extractTitle("## Not H1\n\nText")).toBe("")
  })

  it("returns empty string for empty content", () => {
    expect(extractTitle("")).toBe("")
  })
})

describe("extractLinks", () => {
  it("extracts [[Page Name]] references", () => {
    const links = extractLinks("see [[Other Page]] for details")
    expect(links).toHaveLength(1)
    expect(links[0]).toMatchObject({
      target: "Other Page",
      linkType: "page-ref",
    })
  })

  it("extracts [[Page|Alias]] references", () => {
    const links = extractLinks("see [[Page|Alias]] here")
    expect(links).toHaveLength(1)
    expect(links[0]).toMatchObject({ target: "Page", linkType: "page-ref" })
  })

  it("extracts ((block-id)) references", () => {
    const links = extractLinks("ref ((abc123)) here")
    expect(links).toHaveLength(1)
    expect(links[0]).toMatchObject({ target: "abc123", linkType: "block-ref" })
  })

  it("extracts #tag references", () => {
    const links = extractLinks("tagged #project-alpha here")
    expect(links).toHaveLength(1)
    expect(links[0]).toMatchObject({ target: "project-alpha", linkType: "tag" })
  })

  it("lowercases tag targets", () => {
    const links = extractLinks("#Project-Alpha")
    expect(links[0]?.target).toBe("project-alpha")
  })

  it("extracts multiple link types from mixed content", () => {
    const content = "Page [[Foo]] and ((id-123)) and #tag"
    const links = extractLinks(content)
    expect(links).toHaveLength(3)
    expect(links.map((l) => l.linkType).sort()).toEqual([
      "block-ref",
      "page-ref",
      "tag",
    ])
  })

  it("records correct offset positions", () => {
    const content = "text [[Foo]] text"
    const links = extractLinks(content)
    expect(links[0]?.offset).toBe(5) // [[Foo]] starts at position 5
  })

  it("handles content with no links", () => {
    expect(extractLinks("plain text")).toHaveLength(0)
  })
})
