import { h, Host } from '@stencil/core';
import customPropExamples from '../../types/docExamples';
import { camelToSnakeCase } from '../../utils/stringHelpers';
import { docsSpecialReplace } from './docs-playground-common';
export class DocsPlayground {
  constructor() {
    this.component = '';
    this.docsTags = [];
    this.propDataRaw = undefined;
    this.propDataFormatted = [];
    this.trackInputFor = [];
    this.appliedProps = {};
    this.propData = [];
    this.slotNodes = undefined;
    this.slotNodesWrapped = undefined;
  }
  get hasProps() {
    return this.propData.length > 0;
  }
  get slotContent() {
    var _a;
    return (_a = this.docsTags.find(it => it.name === 'exSlot')) === null || _a === void 0 ? void 0 : _a.text;
  }
  // format raw docs if needed, or...
  componentWillLoad() {
    if (!this.propDataRaw)
      return;
    this.propData = this._formatRawDocs(this.propDataRaw);
  }
  // or use pre-formatted data
  initPropDataState() {
    this.propData = this.propDataFormatted;
    // it seems like stencil clones this for us automagically?
    // at any rate, I think we'd be fine here even if we're init'ing to same ref
  }
  updateComponentProps() {
    const updatedProps = {};
    this.propData.forEach(it => {
      updatedProps[it.name] = this.parseValue(it.currentValue);
    });
    this.appliedProps = updatedProps;
  }
  async formatRawDocs(rawDocs) {
    return this._formatRawDocs(rawDocs);
  }
  _formatRawDocs(rawDocs) {
    return rawDocs.map(doc => {
      var _a;
      let currentValue = (_a = doc.docsTags.find(dt => dt.name == 'ex')) === null || _a === void 0 ? void 0 : _a.text;
      let values = [];
      if (doc.type === 'boolean')
        currentValue = doc.default || 'false';
      // handle simple literal union types - transform to BsSelect-compatible OptionProps
      if (doc.values.some(v => ['string', 'number'].includes(v.type) && v.value)) {
        values = doc.values.map(vIt => {
          const val = this.stringifyValue(vIt.value);
          return {
            label: val,
            value: val,
            disabled: false
          };
        });
      }
      // handle complex custom types - transform to BsSelect-compatible OptionProps
      if (doc.docsTags.some(dt => dt.name == 'mapTo')) {
        values = customPropExamples[doc.docsTags.find(dt => dt.name == 'mapTo').text].map(rawVal => {
          const val = this.stringifyValue(rawVal);
          return {
            label: val,
            value: val,
            disabled: false
          };
        });
        currentValue = this.stringifyValue(currentValue);
      }
      return {
        attr: doc.attr,
        name: doc.name,
        type: doc.type,
        currentValue,
        values
      };
    });
  }
  createSlottedNodes() {
    var _a;
    const slotArr = Array.from((_a = this.slotNodesWrapped) === null || _a === void 0 ? void 0 : _a.childNodes);
    return slotArr.map(it => {
      const classList = it.classList;
      const dataset = it.dataset;
      const attrs = {};
      attrs.outerHTML = it.outerHTML;
      attrs.innerHTML = it.innerHTML;
      let classes = '';
      if (it.nodeName === '#text')
        return it.wholeText;
      for (let i = 0; i < it.attributes.length; i++) {
        const attr = it.attributes.item(i);
        attrs[attr.name] = attr.value;
      }
      for (let key in dataset) {
        attrs[`data-${camelToSnakeCase(key)}`] = it.dataset[key];
      }
      for (const c of classList.values()) {
        classes += `${c} `;
      }
      return h(it.tagName, Object.assign({ class: classes }, attrs));
    });
  }
  handlePropControls(event) {
    const { name, checked, value: newVal } = event.target;
    const idx = this.propData.findIndex(opt => opt.name == name);
    this.propData = this.propData.map((it, i) => {
      if (idx !== i)
        return it;
      if (it.type === 'boolean')
        return Object.assign(Object.assign({}, it), { currentValue: checked });
      return Object.assign(Object.assign({}, it), { currentValue: newVal });
    });
  }
  handleDirectInput(event) {
    if (!this.trackInputFor.includes(this.component))
      return;
    const { checked, value: newVal } = event.target;
    this.propData = this.propData.map(it => {
      if (typeof checked == 'boolean' && it.name === 'checked') {
        return Object.assign(Object.assign({}, it), { currentValue: checked.toString() });
      }
      if (it.name === 'value') {
        return Object.assign(Object.assign({}, it), { currentValue: newVal });
      }
      return it;
    });
  }
  parseValue(val) {
    try {
      return JSON.parse(val);
    }
    catch (err) {
      return val;
    }
  }
  stringifyValue(val) {
    return typeof val == 'string' ?
      val :
      JSON.stringify(val);
  }
  get layoutClass() {
    return this.hasProps ? 'pg-layout' : 'pg-layout-no-props';
  }
  render() {
    if (this.slotNodesWrapped && !this.slotNodes) {
      // Call only once to avoid weird dupe nodes
      this.slotNodes = this.createSlottedNodes();
    }
    return (h(Host, null, h("div", { class: this.layoutClass }, this.hasProps && (h("docs-prop-display", { componentProps: this.propData, onInput: (e) => this.handlePropControls(e) })), h("div", { class: "pg-example-container", onInput: (e) => this.handleDirectInput(e) }, this.component && (h(this.component, Object.assign({}, this.appliedProps), this.slotNodes))), h("docs-code-display", { component: this.component, slotContent: this.slotContent, appliedProps: this.appliedProps }), this.slotContent && (h("span", { style: { display: 'none' }, ref: el => this.slotNodesWrapped = el, innerHTML: docsSpecialReplace(this.slotContent) })))));
  }
  static get is() { return "docs-playground"; }
  static get originalStyleUrls() {
    return {
      "$": ["docs-playground.scss"]
    };
  }
  static get styleUrls() {
    return {
      "$": ["docs-playground.css"]
    };
  }
  static get properties() {
    return {
      "component": {
        "type": "string",
        "mutable": false,
        "complexType": {
          "original": "string",
          "resolved": "string",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": ""
        },
        "attribute": "component",
        "reflect": false,
        "defaultValue": "''"
      },
      "docsTags": {
        "type": "unknown",
        "mutable": false,
        "complexType": {
          "original": "JsonDocsTag[]",
          "resolved": "JsonDocsTag[]",
          "references": {
            "JsonDocsTag": {
              "location": "import",
              "path": "@stencil/core/internal"
            }
          }
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": ""
        },
        "defaultValue": "[]"
      },
      "propDataRaw": {
        "type": "unknown",
        "mutable": false,
        "complexType": {
          "original": "JsonDocsProp[]",
          "resolved": "JsonDocsProp[]",
          "references": {
            "JsonDocsProp": {
              "location": "import",
              "path": "@stencil/core/internal"
            }
          }
        },
        "required": false,
        "optional": true,
        "docs": {
          "tags": [],
          "text": ""
        }
      },
      "propDataFormatted": {
        "type": "unknown",
        "mutable": false,
        "complexType": {
          "original": "FormattedPropDocs[]",
          "resolved": "FormattedPropDocs[]",
          "references": {
            "FormattedPropDocs": {
              "location": "import",
              "path": "../../types/propTypes"
            }
          }
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": ""
        },
        "defaultValue": "[]"
      },
      "trackInputFor": {
        "type": "unknown",
        "mutable": false,
        "complexType": {
          "original": "string[]",
          "resolved": "string[]",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "List components to capture input events emitted from the displayed component.\ne.g. ['bs-input-field', 'bs-switch']"
        },
        "defaultValue": "[]"
      }
    };
  }
  static get states() {
    return {
      "appliedProps": {},
      "propData": {},
      "slotNodes": {},
      "slotNodesWrapped": {}
    };
  }
  static get methods() {
    return {
      "formatRawDocs": {
        "complexType": {
          "signature": "(rawDocs: JsonDocsProp[]) => Promise<FormattedPropDocs[]>",
          "parameters": [{
              "tags": [],
              "text": ""
            }],
          "references": {
            "Promise": {
              "location": "global"
            },
            "FormattedPropDocs": {
              "location": "import",
              "path": "../../types/propTypes"
            },
            "JsonDocsProp": {
              "location": "import",
              "path": "@stencil/core/internal"
            }
          },
          "return": "Promise<FormattedPropDocs[]>"
        },
        "docs": {
          "text": "",
          "tags": []
        }
      }
    };
  }
  static get elementRef() { return "hostEl"; }
  static get watchers() {
    return [{
        "propName": "propDataFormatted",
        "methodName": "initPropDataState"
      }, {
        "propName": "propData",
        "methodName": "updateComponentProps"
      }];
  }
}
//# sourceMappingURL=docs-playground.js.map
