// retoor <retoor@molodetz.nl>

import { Component } from "./Component.js";
import { assetUrl } from "../assetVersion.js";

const CSS_ID = "ai-interaction-css";

export class AiInteraction extends Component {
  static get observedAttributes() {
    return [
      "id",
      "channel",
      "state",
      "mode",
      "title",
      "cancelable",
      "timeout-sec",
      "submit-label",
      "cancel-label",
    ];
  }

  constructor() {
    super();
    this._built = false;
    this._timer = null;
    this._closed = false;
  }

  _ensureCss() {
    if (document.getElementById(CSS_ID)) return;
    const link = document.createElement("link");
    link.id = CSS_ID;
    link.rel = "stylesheet";
    link.href = assetUrl("/static/css/components/ai-interaction.css");
    document.head.appendChild(link);
  }

  connectedCallback() {
    this._ensureCss();
    if (!this._built) {
      this._built = true;
      this._build();
    }
    this._bind();
    this._startTimeout();
  }

  disconnectedCallback() {
    if (this._timer) {
      clearTimeout(this._timer);
      this._timer = null;
    }
  }

  _build() {
    this.classList.add("ai-interaction");
    if (!this.querySelector(".ai-interaction-head")) {
      const head = document.createElement("div");
      head.className = "ai-interaction-head";
      const title = document.createElement("h3");
      title.className = "ai-interaction-title";
      title.textContent = this.attr("title", "Question");
      head.appendChild(title);
      const status = document.createElement("ai-status");
      status.setAttribute("state", this.attr("state", "open"));
      status.className = "ai-interaction-status";
      head.appendChild(status);
      this.insertBefore(head, this.firstChild);
    }
    if (!this.querySelector("ai-actions")) {
      const onlyConfirm =
        this.querySelectorAll("ai-confirm").length === 1 &&
        this.querySelectorAll("ai-choice, ai-choice-multi, ai-field, ai-select").length === 0;
      const actions = document.createElement("ai-actions");
      actions.setAttribute("align", "end");
      actions.setAttribute("submit-label", this.attr("submit-label", "Confirm"));
      actions.setAttribute("cancel-label", this.attr("cancel-label", "Cancel"));
      if (this.boolAttr("cancelable") || this.getAttribute("cancelable") === null) {
        actions.setAttribute("cancelable", "");
      }
      if (onlyConfirm) {
        actions.setAttribute("submit-hidden", "");
      }
      this.appendChild(actions);
    }
  }

  _bind() {
    if (this._bound) return;
    this._bound = true;
    this.addEventListener("click", (event) => {
      const submit = event.target.closest("[data-ai-submit]");
      const cancel = event.target.closest("[data-ai-cancel]");
      if (submit) {
        event.preventDefault();
        this.submit();
      } else if (cancel) {
        event.preventDefault();
        this.cancel("user");
      }
    });
    this.addEventListener("keydown", (event) => {
      if (event.key === "Escape" && this.boolAttr("cancelable") !== false) {
        event.preventDefault();
        this.cancel("escape");
      }
    });
  }

  _startTimeout() {
    const sec = this.intAttr("timeout-sec", 0);
    if (!sec || sec <= 0) return;
    this._timer = setTimeout(() => this.timeout(), sec * 1000);
  }

  collectValues() {
    const values = {};
    const fields = this.querySelectorAll(
      "ai-confirm, ai-choice, ai-choice-multi, ai-field, ai-select"
    );
    for (const field of fields) {
      if (typeof field.getValue !== "function") continue;
      const name = field.getAttribute("name");
      if (!name) continue;
      values[name] = field.getValue();
    }
    return values;
  }

  validate() {
    const fields = this.querySelectorAll(
      "ai-confirm, ai-choice, ai-choice-multi, ai-field, ai-select"
    );
    for (const field of fields) {
      if (typeof field.validate === "function") {
        const result = field.validate();
        if (result && result.valid === false) {
          if (typeof field.focus === "function") field.focus();
          return result;
        }
      }
    }
    return { valid: true };
  }

  submit() {
    if (this._closed) return;
    const validity = this.validate();
    if (!validity.valid) {
      this._setStatus("error", validity.message || "Invalid input");
      return;
    }
    const values = this.collectValues();
    this._close("submitted");
    this.dispatchEvent(
      new CustomEvent("ai:submit", {
        bubbles: true,
        composed: true,
        detail: { values, interaction_id: this.id },
      })
    );
  }

  cancel(reason = "user") {
    if (this._closed) return;
    this._close("cancelled");
    this.dispatchEvent(
      new CustomEvent("ai:cancel", {
        bubbles: true,
        composed: true,
        detail: { reason, interaction_id: this.id },
      })
    );
  }

  timeout() {
    if (this._closed) return;
    this._close("timeout");
    this.dispatchEvent(
      new CustomEvent("ai:timeout", {
        bubbles: true,
        composed: true,
        detail: {
          timeout_sec: this.intAttr("timeout-sec", 0),
          interaction_id: this.id,
        },
      })
    );
  }

  _close(state) {
    this._closed = true;
    this.setAttribute("state", state);
    this._setStatus(state);
    this.querySelectorAll("button, input, select, textarea").forEach((el) => {
      el.disabled = true;
    });
    if (this._timer) {
      clearTimeout(this._timer);
      this._timer = null;
    }
  }

  _setStatus(state, message = "") {
    const status = this.querySelector("ai-status");
    if (!status) return;
    status.setAttribute("state", state);
    if (message) status.setAttribute("message", message);
  }
}

if (!customElements.get("ai-interaction")) {
  customElements.define("ai-interaction", AiInteraction);
}

export default AiInteraction;
