import { Form, Response } from "@samelogic/models";
import { observe } from "selector-observer";
// import { nanoid } from "nanoid/async";
import { Root, createRoot } from "react-dom/client";
// import { MicrosurveyClient } from "./MicrosurveyClient";
import {
  MicrosurveyClient,
  MicrosurveyClientProps,
} from "@samelogic/microsurvey-ui";
import { sendCompletedEvent, sendResponseEvent, sendViewedEvent } from "./api";
import tippy from "tippy.js";
// import "tippy.js/dist/tippy.css"; // optional for styling
import "tippy.js/animations/perspective.css"; // optional for styling

export class SurveyRunner {
  rootId: string = "";
  public container?: HTMLElement;
  public emotionRoot?: HTMLElement;
  public shadowRoot?: HTMLElement;

  sessionId: string = "";
  isRunning: boolean = false;
  runningElement: Element | null = null;
  identity?: string = undefined;
  domRoot: Root | null = null;

  constructor(
    private researchId: string,
    private form: Form
  ) {
    // this.rootId = "sl-root-" + nanoid();
    this.rootId = "sl-root-" + uniqueId();
    this.sessionId = uniqueId();
    this.watchElement();
  }

  private setup() {
    this.container = document.createElement("div");
    this.container.setAttribute("id", this.rootId);
    document.body.appendChild(this.container);

    const shadowContainer = this.container.attachShadow({ mode: "open" });
    const emotionRoot = document.createElement("div");
    const shadowRootElement = document.createElement("div");
    shadowContainer.appendChild(emotionRoot);
    shadowContainer.appendChild(shadowRootElement);

    this.emotionRoot = emotionRoot;
    this.shadowRoot = shadowRootElement;
  }

  private cleanup() {
    // only do shutdown if this is our running element
    if (this.domRoot) {
      this.domRoot.unmount();
      this.domRoot = null;
    }
    this.isRunning = false;
    this.runningElement = null;

    if (this.container) {
      this.container.remove();
    }
  }

  public setIdentity(identity?: string) {
    this.identity = identity;
  }

  private handleElementEvent = (event: Event, anchor: Element) => {
    // console.log("event click");
    //TODO: event.preventDefault(); and event.preventPropagation(); here when needed to stop default behavior
    // if (this.props.preventDefault) {
    event.preventDefault();
    // }

    // prevent multiple microsurveys from being triggered
    if (this.isRunning) return;

    // trigger microsurvey
    this.setup();
    // renderForm(this.container!, event.target as HTMLElement, this.form);

    const domRoot = createRoot(this.shadowRoot!);
    if (!this.form.settings?.anchorEl) {
      console.log("samelogic: error, no anchor element specified");
      return;
    }
    // const anchor = document.querySelector(this.form.settings?.anchorEl!);
    // console.log("anchor");
    // console.log(anchor);

    const props: MicrosurveyClientProps = {
      form: this.form,
      // page?: number,
      // open?: boolean;
      anchorEl: anchor,
      container: null,
      styleRoot: this.emotionRoot,

      onClosed: () => {
        // console.log("form closed!");
        // this.isRunning = false;
        this.cleanup();
      },
      onAnswer: (formResponse: Response) => {
        // console.log("form answer!");
        // console.log(formResponse);
        sendResponseEvent(
          this.researchId,
          this.sessionId,
          formResponse,
          this.identity
        );
      },
      onSubmit: (formResponse: Response) => {
        // console.log("form completed!");
        // console.log(formResponse);
        sendCompletedEvent(
          this.researchId,
          this.sessionId,
          formResponse,
          this.identity
        );
      },
    };

    // start showing
    this.isRunning = true;
    this.runningElement = anchor;
    domRoot.render(<MicrosurveyClient {...props} />);
    this.domRoot = domRoot;

    sendViewedEvent(this.researchId, this.sessionId);
  };

  // https://github.com/samelogic/samelogic.js/blob/master/sdks/samelogic.js/src/workflows/Triggers/TriggerEvent/EventStrategies/PageEventStrategy.ts
  private watchPage() {}
  // https://github.com/samelogic/samelogic.js/blob/master/sdks/samelogic.js/src/workflows/Triggers/TriggerEvent/EventStrategies/ElementEventStrategy.ts
  private activeElements: Set<Element> = new Set();

  private watchElement() {
    const selector = this.form.settings?.anchorEl;
    if (!selector) return;

    if (this.form.settings?.trigger?.type == "hover") {
      const tip = this.form.settings.trigger.hoverToolTip || " ";
      observe(selector, {
        add: (el) => {
          if (isWithinTippy(el) || this.activeElements.has(el)) return;

          const iconHtml = `
            <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-hand-click"><path d="M0 0h24v24H0z" stroke="none"/><path d="M8 13V4.5a1.5 1.5 0 0 1 3 0V12m0-.5v-2a1.5 1.5 0 0 1 3 0V12m0-1.5a1.5 1.5 0 0 1 3 0V12"/><path d="M17 11.5a1.5 1.5 0 0 1 3 0V16a6 6 0 0 1-6 6h-2 .208a6 6 0 0 1-5.012-2.7L7 19q-.468-.718-3.286-5.728a1.5 1.5 0 0 1 .536-2.022 1.87 1.87 0 0 1 2.28.28L8 13M5 3 4 2m0 5H3m11-4 1-1m0 4h1"/></svg>`;

          const tooltipContent = `
            <div style="display: flex; align-items: center;">
              ${iconHtml}
              <span style="margin-left: 8px;">${tip}</span>
            </div>
          `;

          const instance = tippy(el, {
            content: tooltipContent,
            allowHTML: true,
            interactive: true,
            hideOnClick: true,
            animation: "perspective",
            interactiveBorder: 12,
            interactiveDebounce: 1000,
            onShow: (instance) => {
              if (this.activeElements.has(el)) {
                instance.disable();
                return false;
              }
              const box = instance.popper.querySelector(
                ".tippy-box"
              ) as HTMLElement;
              const content = box.querySelector(
                ".tippy-content"
              ) as HTMLElement;

              // Style the content box for rounded borders and drop shadow
              content.style.padding = "10px 20px";
              content.style.borderRadius = "200px";
              content.style.boxShadow = "0px 4px 8px rgba(0, 0, 0, 0.3)";
              content.style.background = "rgba(0, 0, 0, 0.85)";
              content.style.cursor = "pointer";
              content.style.fontSize = "13px";
              content.style.color = "#fff";
              content.style.fontWeight = "550";

              // Ensure the icon and text are aligned
              const icon = content.querySelector("svg");
              if (icon) {
                icon.style.marginRight = "8px";
              }
            },
          });

          instance.popper.addEventListener("click", (evt) => {
            if (!this.activeElements.has(el)) {
              this.handleElementEvent(evt, el);
              this.activeElements.add(el);
              instance.hide();
              instance.disable();
            }
          });
        },
        remove: (el) => {
          if (isWithinTippy(el)) return;

          if (this.runningElement == el) {
            this.cleanup();
          }
          this.activeElements.delete(el);
        },
      });
    } else if (this.form.settings?.trigger?.type == "click") {
      observe(selector, {
        add: (el) => {
          if (isWithinTippy(el) || this.activeElements.has(el)) return;

          el.addEventListener("click", (evt) => {
            if (!this.activeElements.has(el)) {
              this.handleElementEvent(evt, el);
              this.activeElements.add(el);
            }
          });
        },
        remove: (el) => {
          if (isWithinTippy(el)) return;

          if (this.runningElement == el) {
            this.cleanup();
          }
          this.activeElements.delete(el);
        },
      });
    }
  }
}

// https://paulius-repsys.medium.com/simplest-possible-way-to-generate-unique-id-in-javascript-a0d7566f3b0c
function uniqueId(): string {
  const dateString = Date.now().toString(36);
  const randomness = Math.random().toString(36).substr(2);
  return dateString + randomness;
}

function isWithinTippy(el: Element) {
  // check all the way up top
  // if tippy is found, return true
  while (el != null) {
    if (el.classList.contains("tippy-content")) {
      return true;
    }
    if (el.id.startsWith("tippy")) return true;
    if (el instanceof HTMLElement && el.dataset.tippy) return true;

    el = el.parentElement!;
  }

  return false;
}
