import {
  cleanElement,
  getParamsFromComponent,
  getUrlFromComponent,
} from "./utils";
import { fetchUserTenants, fetchUserTokens } from "./api";
import { Theme } from "./models";

export {
  sendHTMLContentToHost,
  sendHTMLContentToIframe,
  proxyContextPostMessage,
} from "./context-share";

export default class MentorAI extends HTMLElement {
  isEmbeddedMentorReady: boolean = false;
  iblData: string = "";
  // Keeps track of the hosts' page URL
  lastUrl: string = "";
  private iframeContexts: { [key: string]: string } = {}; // Object to keep track of iframe contexts

  constructor() {
    super();
    const _iblData: string | null = new URL(
      window.location.href
    ).searchParams.get("ibl-data");
    if (_iblData) {
      this.iblData = _iblData;
    }
    this.attachShadow({ mode: "open" });

    const template = `
    <style>
        iframe {
        border: 0px white;
        height: 100%;
        width: 100%;
        border-radius: 0;
        }
        #ibl-chat-widget-container {
            /* border: 1px solid #dfdfdf; */
            height: 100%;
            position: relative;
        }
        @media screen and (max-width: 768px) {
        #ibl-chat-widget-container {

        }
        img.ibl-chat-bubble {
            right: 20px !important;
        }
        }
        .spinner {
            border: 3px solid #f3f3f3; /* Light grey */
            border-top: 3px solid #6cafe1; /* Blue */
            border-radius: 50%;
            width: 40px;
            height: 40px;
            animation: spin 1s linear infinite;
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            display: block; /* Initially hidden */
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
    </style>
    <div id="ibl-chat-widget-container">
        <div class="spinner" id="loading-spinner"></div>
        <iframe
          allow="clipboard-read; clipboard-write"
          onload="this.parentNode.querySelector('#loading-spinner').style.display='none';"
          onloadstart="this.parentNode.querySelector('#loading-spinner').style.display='block';"
        ></iframe>
    </div>
        `;
    if (this.shadowRoot) {
      this.shadowRoot.innerHTML = template;
    }
  }

  async onPostMessage(event: MessageEvent) {
    let message: any = event.data;
    if (typeof message === "string") {
      try {
        message = JSON.parse(message);
      } catch (error) {
        return;
      }
    }

    // New context handling
    if (message?.type === "context") {
      const origin = event.origin; // Get the origin of the iframe
      if (this.contextOrigins.includes(origin)) {
        // Check if the origin is whitelisted
        this.iframeContexts[origin] = message.data; // Store the context data
      }
    }

    if (message?.closeEmbed) {
      window.parent.postMessage(JSON.stringify(message), "*");
    }

    // New height handling
    if (message?.height) {
      const container = this.shadowRoot?.querySelector(
        "#ibl-chat-widget-container"
      ) as HTMLElement;
      if (container) {
        container.style.height = `${message.height}px`; // Set the height based on the message
      }
    }

    if (!this.isAnonymous) {
      if (
        message?.loaded &&
        (!message.auth.axd_token ||
          !message.auth.dm_token ||
          message.auth.tenant !== this.tenant ||
          this.isTokenExpired(message.auth.dm_token_expires) ||
          this.isTokenExpired(message.auth.axd_token_expires))
      ) {
        try {
          const userTenants = await fetchUserTenants(this.lmsUrl);

          const selectedTenant = userTenants.find(
            (tenant) => tenant.key === this.tenant
          );
          if (selectedTenant) {
            const userTokens = await fetchUserTokens(
              this.lmsUrl,
              selectedTenant.key
            );
            const userObject = {
              axd_token: userTokens.axd_token.token,
              axd_token_expires: userTokens.axd_token.expires,
              userData: JSON.stringify(userTokens.user),
              dm_token_expires: userTokens.dm_token.expires,
              tenant: selectedTenant.key,
              tenants: JSON.stringify(userTenants),
              dm_token: userTokens.dm_token.token,
            };
            this.sendAuthDataToIframe(userObject);
          }
        } catch (error) {}
        !this.iblData && this.redirectToAuthSPA();
      }

      if (message?.loaded && message.auth.userData) {
        try {
          if (
            this.edxUserId &&
            this.edxUserId !=
              JSON.parse(message.auth.userData).user_id.toString()
          ) {
            if (this.iblData) {
              this.sendAuthDataToIframe(this.iblData);
            } else {
              try {
                const userTenants = await fetchUserTenants(this.lmsUrl);

                const selectedTenant = userTenants.find(
                  (tenant) => tenant.key === this.tenant
                );
                if (selectedTenant) {
                  const userTokens = await fetchUserTokens(
                    this.lmsUrl,
                    selectedTenant.key
                  );
                  const userObject = {
                    axd_token: userTokens.axd_token.token,
                    axd_token_expires: userTokens.axd_token.expires,
                    userData: JSON.stringify(userTokens.user),
                    dm_token_expires: userTokens.dm_token.expires,
                    tenant: selectedTenant.key,
                    tenants: JSON.stringify(userTenants),
                    dm_token: userTokens.dm_token.token,
                  };
                  this.sendAuthDataToIframe(userObject);
                }
              } catch (error) {}
            }
          }
        } catch (error) {
          console.error("Error parsing userData from auth:", error);
        }
      }
    }
    if (message?.authExpired) {
      if (!this.isAnonymous) {
        if (this.iblData) {
          this.sendAuthDataToIframe(this.iblData);
        } else {
          this.redirectToAuthSPA(true);
        }
      }
    } else if (message?.ready) {
      this.isEmbeddedMentorReady = true;
      if (this.iblData) {
        this.sendAuthDataToIframe(this.iblData);
      } else if (!this.authRelyOnHost) {
        if (!this.isAnonymous) {
          this.redirectToAuthSPA();
        }
      }
    }
    if (message?.loaded) {
      this.isEmbeddedMentorReady = true;
      if (this.isContextAware) {
        this.sendHostInfoToIframe();
      }
      if (this.theme) {
        this.switchTheme(this.theme);
      }

      if (this.documentFilter) {
        this.sendDocumentFilterToIframe();
      }

      if (this.edxUsageId) {
        this.sendDataToIframe({
          type: "MENTOR:EDX_USAGE_ID",
          data: { edxUsageId: this.edxUsageId },
        });
      }
      if (this.edxCourseId) {
        this.sendDataToIframe({
          type: "MENTOR:EDX_COURSE_ID",
          data: { edxCourseId: this.edxCourseId },
        });
      }
    }
  }
  connectedCallback() {
    if (this.iblData) {
      const url = new URL(window.location.href);
      url.searchParams.delete("ibl-data");
      window.history.replaceState({}, document.title, url);
      const userData: any = JSON.parse(this.iblData).userData;
      document.cookie = `userData=${userData}; domain=${document.domain}; path=/;`;
    }

    window.addEventListener("message", (event: MessageEvent) =>
      this.onPostMessage(event)
    );

    // Show the spinner when the iframe starts loading
    const iframe = this.shadowRoot?.querySelector("iframe");
    if (iframe) {
      iframe.onloadstart = () => {
        const spinner = this.shadowRoot?.querySelector(
          "#loading-spinner"
        ) as HTMLElement;
        if (spinner) {
          spinner.style.display = "block";
        }
      };
      iframe.onload = () => {
        const spinner = this.shadowRoot?.querySelector(
          "#loading-spinner"
        ) as HTMLElement;
        if (spinner) {
          spinner.style.display = "none";
        }
      };
    }
  }

  disconnectedCallback() {
    window.removeEventListener("message", this.onPostMessage);
  }

  get mentorUrl() {
    return this.getAttribute("mentorurl") || "https://mentor.iblai.app";
  }

  set mentorUrl(value) {
    this.setAttribute("mentorurl", value);
  }

  get authUrl() {
    return this.getAttribute("authurl") || "https://auth.iblai.app";
  }

  set authUrl(value) {
    this.setAttribute("authurl", value);
  }

  get lmsUrl() {
    return this.getAttribute("lmsurl") || "https://learn.iblai.app";
  }

  set lmsUrl(value) {
    this.setAttribute("lmsurl", value);
  }

  get theme(): Theme {
    return (this.getAttribute("theme") as Theme) || "light";
  }

  set theme(value: Theme) {
    this.setAttribute("theme", value);
  }

  get tenant(): string | null {
    return this.getAttribute("tenant");
  }

  set tenant(value: string) {
    this.setAttribute("tenant", value);
  }

  get extraParams(): string | null {
    return this.getAttribute("extraparams");
  }

  set extraParams(value: string) {
    this.setAttribute("extraparams", value);
  }

  get contextOrigins(): string[] {
    return this.getAttribute("contextorigins")?.split(",") || [];
  }

  set contextOrigins(value: string) {
    this.setAttribute("contextorigins", value);
  }

  get mentor(): string | null {
    return this.getAttribute("mentor");
  }

  set mentor(value: string) {
    this.setAttribute("mentor", value);
  }

  get edxUsageId(): string | null {
    return this.getAttribute("edxusageid");
  }

  set edxUsageId(value: string) {
    this.setAttribute("edxusageid", value);
  }

  get edxCourseId(): string | null {
    return this.getAttribute("edxcourseid");
  }

  set edxCourseId(value: string) {
    this.setAttribute("edxcourseid", value);
  }

  get edxUserId(): string | null {
    return this.getAttribute("edxuserid");
  }

  set edxUserId(value: string) {
    this.setAttribute("edxuserid", value);
  }

  get authRelyOnHost() {
    return this.hasAttribute("authrelyonhost");
  }

  set authRelyOnHost(value) {
    if (value) {
      this.setAttribute("authrelyonhost", "");
    } else {
      this.removeAttribute("authrelyonhost");
    }
  }

  get isAnonymous() {
    return this.hasAttribute("isanonymous");
  }

  set isAnonymous(value) {
    if (value) {
      this.setAttribute("isanonymous", "");
    } else {
      this.removeAttribute("isanonymous");
    }
  }

  get isAdvanced() {
    return this.hasAttribute("isadvanced");
  }

  set isAdvanced(value) {
    if (value) {
      this.setAttribute("isadvanced", "");
    } else {
      this.removeAttribute("isadvanced");
    }
  }

  get isContextAware() {
    return this.hasAttribute("iscontextaware");
  }

  set isContextAware(value) {
    if (value) {
      this.setAttribute("iscontextaware", "");
    } else {
      this.removeAttribute("iscontextaware");
    }
  }

  get redirectToken(): string | null {
    return this.getAttribute("redirecttoken");
  }

  set redirectToken(value: string) {
    this.setAttribute("redirecttoken", value);
  }

  get component(): "chat" | null {
    return this.getAttribute("component") as "chat" | null;
  }

  set component(value: string) {
    this.setAttribute("component", value);
  }

  get modal(): "dataset" | "settings" | null {
    return this.getAttribute("modal") as "dataset" | "settings" | null;
  }

  set modal(value: string) {
    this.setAttribute("modal", value);
  }

  get documentFilter(): string | null {
    return this.getAttribute("documentfilter") as string | null;
  }

  set documentFilter(value: string) {
    this.setAttribute("documentfilter", value);
  }

  static get observedAttributes() {
    return [
      "mentorUrl",
      "tenant",
      "mentor",
      "isadvanced",
      "iscontextaware",
      "contextOrigins", // Add the new attribute to observed attributes
      "component",
      "modal",
      "extraparams",
      "documentfilter",
    ];
  }

  attributeChangedCallback(name: string, oldValue: any, newValue: any) {
    if (
      [
        "mentorUrl",
        "tenant",
        "mentor",
        "isadvanced",
        "component",
        "modal",
        "extraparams",
      ].includes(name)
    ) {
      const iframe = this.shadowRoot?.querySelector("iframe");
      if (this.shadowRoot && iframe) {
        iframe.src = `${this.mentorUrl}/platform/${
          this.tenant
        }${getUrlFromComponent(this.component, this.mentor)}/${
          this.modal ? this.modal : ""
        }?embed=true&mode=anonymous&extra-body-classes=iframed-externally${
          this.isAdvanced ? "&chat=advanced" : ""
        }${this.modal ? "&modal=" + this.modal : ""}${getParamsFromComponent(
          this.component
        )}${this.extraParams ? "&" + this.extraParams : ""}`;
      }
    }
    if (this.isContextAware) {
      this.lastUrl = window.location.href;
      setInterval(() => {
        // const currentUrl = window.location.href;
        // if (currentUrl !== this.lastUrl) {
        //   this.lastUrl = currentUrl;
        //   this.isContextAware && this.sendHostInfoToIframe();
        // }
        this.isContextAware && this.sendHostInfoToIframe();
      }, 1000);
    }
    if (this.documentFilter) {
      this.sendDocumentFilterToIframe();
    }
    if (name === "contextOrigins") {
      this.contextOrigins = newValue?.split(",") || []; // Update the context origins when the attribute changes
    }
    if (name === "theme") {
      this.switchTheme(newValue);
    }
  }

  getCleanBodyContent(): string {
    const bodyClone: HTMLElement = document.body.cloneNode(true) as HTMLElement;

    // Clean the bodyClone
    cleanElement(bodyClone.outerHTML);

    const removeComments = (node: Node) => {
      for (let i = 0; i < node.childNodes.length; i++) {
        const child = node.childNodes[i];
        if (child.nodeType === 8) {
          node.removeChild(child);
          i--;
        } else if (child.nodeType === 1) {
          removeComments(child);
        }
      }
    };
    removeComments(bodyClone);

    // Clean each iframeContext (HTML string) and merge their HTML
    const iframeHtmls = Object.values(this.iframeContexts).map(
      (iframeHtml: string) => {
        return cleanElement(iframeHtml); // Clean unwanted selectors
      }
    );

    // Merge bodyClone HTML with cleaned iframe HTMLs
    const mergedContent = bodyClone.innerHTML + iframeHtmls.join("");

    return mergedContent; // Return the merged HTML content
  }

  sendHostInfoToIframe() {
    const iframe = this.shadowRoot?.querySelector(
      "#ibl-chat-widget-container iframe"
    ) as HTMLIFrameElement;
    if (iframe && iframe.contentWindow) {
      const bodyContent = this.getCleanBodyContent();
      const payload = {
        type: "MENTOR:CONTEXT_UPDATE",
        hostInfo: {
          title: document.title,
          href: window.location.href,
        },
        pageContent: bodyContent,
      };
      iframe.contentWindow.postMessage(payload, "*");
    }
  }

  sendDocumentFilterToIframe() {
    this.sendDataToIframe({
      type: "MENTOR:DOCUMENTFILTER",
      data: this.documentFilter,
    });
  }

  sendDataToIframe(data: Record<string, any>) {
    const iframe = this.shadowRoot?.querySelector(
      "#ibl-chat-widget-container iframe"
    ) as HTMLIFrameElement;
    if (iframe && iframe.contentWindow) {
      iframe.contentWindow.postMessage(data, "*");
    }
  }

  switchTheme(theme: string) {
    const iframe = this.shadowRoot?.querySelector(
      "#ibl-chat-widget-container iframe"
    ) as HTMLIFrameElement;
    if (iframe && iframe.contentWindow) {
      iframe.contentWindow.postMessage(JSON.stringify({ theme }), "*");
    }
  }

  sendAuthDataToIframe(iblData: any) {
    const iframe = this.shadowRoot?.querySelector(
      "#ibl-chat-widget-container iframe"
    ) as HTMLIFrameElement;
    if (iframe && iframe.contentWindow) {
      iframe.contentWindow.postMessage(iblData, "*");
    }
  }

  isTokenExpired(token_expires: string) {
    const expirationDate = new Date(token_expires);
    const now = new Date();
    return now >= expirationDate;
  }

  redirectToAuthSPA(forceLogout?: boolean) {
    if (this.authRelyOnHost) {
      const iframe = this.shadowRoot?.querySelector(
        "#ibl-chat-widget-container iframe"
      ) as HTMLIFrameElement;
      if (iframe && iframe.contentWindow) {
        iframe.contentWindow.postMessage({ ...localStorage }, "*");
      }
      return;
    }
    const redirectPath: string =
      window.location.pathname + window.location.search;
    window.location.href = `${
      this.authUrl
    }/login?redirect-path=${redirectPath}&tenant=${this.tenant}${
      forceLogout ? "&logout=true" : ""
    }&redirect-token=${this.redirectToken}`;
  }

  toggleWidget() {
    const widget: HTMLElement | null = document.getElementById(
      "ibl-chat-widget-container"
    );
    if (widget) {
      if (widget.style.display === "none") {
        widget.style.display = "";
      } else {
        widget.style.display = "none";
      }
    }
  }
}

function defineMentorAI() {
  if (typeof window !== "undefined" && !customElements.get("mentor-ai")) {
    customElements.define("mentor-ai", MentorAI);
  }
}

defineMentorAI();

export * from "./mentor-ai";
