import { ElementPart, nothing } from 'lit'
import { directive, Directive, PartInfo, PartType } from 'lit/directive.js'

export type DataAttributeMap = Record<string, string | number | boolean>

class DataAttrDirective extends Directive {
  rendered?: DataAttributeMap

  constructor(partInfo: PartInfo) {
    super(partInfo)
    if (partInfo.type !== PartType.ELEMENT) {
      throw new Error('dataAttr() can only be used on an element')
    }
  }

  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  override render(attributes: DataAttributeMap): typeof nothing | string {
    return nothing
  }

  override update(part: ElementPart, props: unknown[]): unknown | string {
    const element = part.element as HTMLElement
    const map = props[0] as DataAttributeMap
    if (!map) {
      this.clearRendered(element)
      return nothing
    }
    const keys = Object.keys(map)
    if (!keys.length) {
      this.clearRendered(element)
      return nothing
    }
    this.clearRendered(element, keys)
    this.rendered = map
    const { dataset } = element
    keys.forEach((key) => {
      const value = String(map[key])
      if (dataset[key] === value) {
        return
      }
      dataset[key] = value
    })
    return nothing
  }

  clearRendered(element: HTMLElement, keep: string[] = []): void {
    const { rendered } = this
    if (!rendered) {
      return
    }
    const keys = Object.keys(rendered)
    if (!keys.length) {
      return
    }
    const { dataset } = element
    keys.forEach((key) => {
      if (keep.includes(key)) {
        return
      }
      // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
      delete dataset[key]
    })
  }
}

export const dataAttr = directive(DataAttrDirective)
