import { EditorView, ViewPlugin, ViewUpdate, WidgetType, Decoration } from "@codemirror/view"
import { RangeSetBuilder } from "@codemirror/state"
import { Todo } from "./todo"

class CountdownWidget extends WidgetType {
  duration: number
  startedAt?: number
  intervalId?: number
  view: EditorView

  constructor(duration: number, view: EditorView) {
    super()
    this.duration = duration * 1000
    this.view = view
  }

  startTimer() {
    if (this.startedAt) return
    this.view.dom.classList.add("timer-running")
    this.startedAt = Date.now()

    if (Notification.permission === "default") {
      Notification.requestPermission()
    }
  }

  stopTimer() {
    this.view.dom.classList.remove("timer-running")

    if (this.intervalId) {
      clearInterval(this.intervalId)
      this.intervalId = undefined
    }
    this.startedAt = undefined
  }

  toggleTimer() {
    if (this.startedAt) {
      this.updateDOM(this.toDOM(), this.view)
      this.stopTimer()
    } else {
      this.startTimer()
    }
  }

  toDOM(): HTMLElement {
    const span = document.createElement("span")
    span.className = "countdown-timer"

    span.addEventListener("mousedown", (e) => {
      this.toggleTimer()
    })

    const updateTimer = async () => {
      if (this.startedAt) {
        span.classList.add("running")
      } else {
        span.classList.remove("running")
      }

      if (!this.startedAt) {
        span.textContent = "▶"
        return
      }

      const elapsed = Date.now() - this.startedAt
      const remaining = this.duration - elapsed

      if (remaining <= 0) {
        span.textContent = "00:00"
        span.classList.remove("running")
        span.classList.add("finished")
        this.stopTimer()
        // Only play sound in browser environment (not during SSR)
        const { zzfx } = await import("zzfx")
        zzfx(...[1.2, , 117, 0.03, 0.01, 0.12, , 2.1, , , , , , 1.3, , 0.3, 0.08, 0.6, 0.1, , 1946]) // Hit 107
        this.showNotification()
        return
      }

      const seconds = Math.ceil(remaining / 1000)
      const minutes = Math.floor(seconds / 60)
      const secondsRemainder = seconds % 60
      span.textContent = `${minutes.toString().padStart(2, "0")}:${secondsRemainder
        .toString()
        .padStart(2, "0")}`
    }

    updateTimer()
    this.intervalId = setInterval(updateTimer, 100) as any

    return span
  }

  private async showNotification() {
    if (Notification.permission === "default") {
      console.log("Requesting notification permission...")
      await Notification.requestPermission()
    }

    if (Notification.permission === "granted") {
      new Notification("⏰ Timer Finished!", {
        body: "Your countdown timer has reached zero.",
        icon: "⏰",
        requireInteraction: true,
        tag: "countdown-timer",
      })
    } else {
      console.log("Notification permission denied or blocked")
    }
  }

  override destroy() {
    if (this.intervalId) {
      clearInterval(this.intervalId)
      this.intervalId = undefined
    }
  }
}

export const todoTimer = ViewPlugin.fromClass(
  class {
    decorations: any
    currentWidget?: CountdownWidget

    constructor(view: EditorView) {
      this.decorations = this.buildDecorations(view)
    }

    update(update: ViewUpdate) {
      if (!update.selectionSet) return
      if (this.currentWidget?.startedAt) return

      this.decorations = this.buildDecorations(update.view)
    }

    buildDecorations(view: EditorView) {
      const builder = new RangeSetBuilder<Decoration>()
      const { doc, selection } = view.state
      const line = doc.lineAt(selection.main.head)

      const todo = Todo.parse(line.text)
      if (!todo?.timeEstimate || todo.done) {
        this.currentWidget = undefined
        return builder.finish()
      }

      builder.add(line.from, line.from, Decoration.line({ class: "cm-timer" }))
      this.currentWidget = new CountdownWidget(todo.timeEstimate, view)
      const decoration = Decoration.widget({ widget: this.currentWidget, side: 1 })

      builder.add(line.to, line.to, decoration)
      return builder.finish()
    }
  },
  { decorations: (v) => v.decorations }
)
