'use strict';

Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });

const constants = require('./constants.cjs');
const ParentNode = require('./ParentNode.cjs');
const NamedNodeMap = require('./NamedNodeMap.cjs');
const Attr = require('./Attr.cjs');
const serialization = require('./serialization.cjs');

class Element extends ParentNode.ParentNode {
  nodeType = (() => constants.NodeType.ELEMENT_NODE)();
  [constants.NS] = (() => constants.NamespaceURI.XHTML)();
  get namespaceURI() {
    return this[constants.NS];
  }
  get tagName() {
    return this.nodeName;
  }
  get slot() {
    return this.getAttribute('slot') ?? '';
  }
  set slot(slot) {
    const finalSlot = String(slot);
    if (this.getAttribute('slot') !== finalSlot) {
      this.attributes.setNamedItem(new Attr.Attr('slot', finalSlot));
    }
  }
  get attributes() {
    let attributes = this[constants.ATTRIBUTES];
    if (!attributes) {
      attributes = new NamedNodeMap.NamedNodeMap(this);
      this[constants.ATTRIBUTES] = attributes;
    }
    return attributes;
  }
  getAttributeNames() {
    return [...this.attributes].map(attr => attr.name);
  }
  get firstElementChild() {
    return this.children[0] ?? null;
  }
  get lastElementChild() {
    return this.children[this.children.length - 1] ?? null;
  }
  get nextElementSibling() {
    let sib = this.nextSibling;
    while (sib && sib.nodeType !== 1) sib = sib.nextSibling;
    return sib;
  }
  get previousElementSibling() {
    let sib = this.previousSibling;
    while (sib && sib.nodeType !== 1) sib = sib.previousSibling;
    return sib;
  }
  setAttribute(name, value) {
    this.attributes.setNamedItem(new Attr.Attr(name, String(value)));
  }
  setAttributeNS(namespace, name, value) {
    this.attributes.setNamedItemNS(new Attr.Attr(name, String(value), namespace));
  }
  getAttribute(name) {
    const attr = this.attributes.getNamedItem(name);
    return attr && attr.value;
  }
  getAttributeNS(namespace, name) {
    const attr = this.attributes.getNamedItemNS(namespace, name);
    return attr && attr.value;
  }
  hasAttribute(name) {
    const attr = this.attributes.getNamedItem(name);
    return attr != null;
  }
  hasAttributeNS(namespace, name) {
    const attr = this.attributes.getNamedItemNS(namespace, name);
    return attr != null;
  }
  removeAttribute(name) {
    this.attributes.removeNamedItem(name);
  }
  removeAttributeNS(namespace, name) {
    this.attributes.removeNamedItemNS(namespace, name);
  }
  get outerHTML() {
    return serialization.serializeNode(this);
  }
  get innerHTML() {
    return serialization.serializeChildren(this);
  }
  set innerHTML(html) {
    if (html == null || html === '') {
      this.replaceChildren();
    } else {
      const fragment = serialization.parseHtml(String(html), this);
      this.replaceChildren(fragment);
    }
  }
}

exports.Element = Element;
