import { tracked } from "@glimmer/tracking";
import { htmlSafe } from "@ember/template";
import { TrackedArray } from "@ember-compat/tracked-built-ins";
import { ajax } from "discourse/lib/ajax";
import { bind } from "discourse/lib/decorators";
import { autoUpdatingRelativeAge } from "discourse/lib/formatter";
import { withPluginApi } from "discourse/lib/plugin-api";
import { i18n } from "discourse-i18n";
import AiBotSidebarEmptyState from "../discourse/components/ai-bot-sidebar-empty-state";
import AiBotSidebarNewConversation from "../discourse/components/ai-bot-sidebar-new-conversation";
import { AI_CONVERSATIONS_PANEL } from "../discourse/services/ai-conversations-sidebar-manager";

export default {
  name: "ai-conversations-sidebar",

  initialize() {
    withPluginApi((api) => {
      const siteSettings = api.container.lookup("service:site-settings");
      if (!siteSettings.ai_bot_enable_dedicated_ux) {
        return;
      }

      const currentUser = api.container.lookup("service:current-user");
      if (!currentUser) {
        return;
      }

      const aiConversationsSidebarManager = api.container.lookup(
        "service:ai-conversations-sidebar-manager"
      );
      const appEvents = api.container.lookup("service:app-events");
      const messageBus = api.container.lookup("service:message-bus");
      const navigationMenu = api.container.lookup("service:navigationMenu");

      api.addSidebarPanel(
        (BaseCustomSidebarPanel) =>
          class AiConversationsSidebarPanel extends BaseCustomSidebarPanel {
            key = AI_CONVERSATIONS_PANEL;
            hidden = true;
            displayHeader = !navigationMenu.isHeaderDropdownMode;
            expandActiveSection = true;
          }
      );

      api.renderInOutlet(
        "before-sidebar-sections",
        AiBotSidebarNewConversation
      );
      api.addSidebarSection(
        (BaseCustomSidebarSection, BaseCustomSidebarSectionLink) => {
          const AiConversationLink = class extends BaseCustomSidebarSectionLink {
            route = "topic.fromParamsNear";

            constructor(topic) {
              super(...arguments);
              this.topic = topic;
            }

            get key() {
              return this.topic.id;
            }

            get name() {
              return this.topic.title;
            }

            get models() {
              return [
                this.topic.slug,
                this.topic.id,
                this.topic.last_read_post_number || 0,
              ];
            }

            get title() {
              return this.topic.title;
            }

            get text() {
              return this.topic.title;
            }

            get classNames() {
              return `ai-conversation-${this.topic.id}`;
            }
          };

          return class extends BaseCustomSidebarSection {
            @tracked links = new TrackedArray();
            @tracked topics = [];
            @tracked hasMore = [];
            @tracked loadedTodayLabel = false;
            @tracked loadedSevenDayLabel = false;
            @tracked loadedThirtyDayLabel = false;
            @tracked loadedMonthLabels = new Set();
            page = 0;
            isFetching = false;
            totalTopicsCount = 0;

            constructor() {
              super(...arguments);
              this.fetchMessages();

              appEvents.on(
                "discourse-ai:bot-pm-created",
                this,
                "addNewPMToSidebar"
              );
            }

            @bind
            willDestroy() {
              this.removeScrollListener();
              appEvents.off(
                "discourse-ai:bot-pm-created",
                this,
                "addNewPMToSidebar"
              );
            }

            get name() {
              return "ai-conversations-history";
            }

            get emptyStateComponent() {
              return AiBotSidebarEmptyState;
            }

            get text() {
              return i18n(
                "discourse_ai.ai_bot.conversations.messages_sidebar_title"
              );
            }

            get sidebarElement() {
              return document.querySelector(
                ".sidebar-wrapper .sidebar-sections"
              );
            }

            addNewPMToSidebar(topic) {
              // Reset category labels since we're adding a new topic
              this.loadedTodayLabel = false;
              this.loadedSevenDayLabel = false;
              this.loadedThirtyDayLabel = false;
              this.loadedMonthLabels.clear();

              this.topics = [topic, ...this.topics];
              this.buildSidebarLinks();

              this.watchForTitleUpdate(topic);
            }

            @bind
            removeScrollListener() {
              const sidebar = this.sidebarElement;
              if (sidebar) {
                sidebar.removeEventListener("scroll", this.scrollHandler);
              }
            }

            @bind
            attachScrollListener() {
              const sidebar = this.sidebarElement;
              if (sidebar) {
                sidebar.addEventListener("scroll", this.scrollHandler);
              }
            }

            @bind
            scrollHandler() {
              const sidebarElement = this.sidebarElement;
              if (!sidebarElement) {
                return;
              }

              const scrollPosition = sidebarElement.scrollTop;
              const scrollHeight = sidebarElement.scrollHeight;
              const clientHeight = sidebarElement.clientHeight;

              // When user has scrolled to bottom with a small threshold
              if (scrollHeight - scrollPosition - clientHeight < 100) {
                if (this.hasMore && !this.isFetching) {
                  this.loadMore();
                }
              }
            }

            async fetchMessages(isLoadingMore = false) {
              if (this.isFetching) {
                return;
              }

              try {
                this.isFetching = true;
                const data = await ajax(
                  "/discourse-ai/ai-bot/conversations.json",
                  {
                    data: { page: this.page, per_page: 40 },
                  }
                );

                if (isLoadingMore) {
                  this.topics = [...this.topics, ...data.conversations];
                } else {
                  this.topics = data.conversations;
                }

                this.totalTopicsCount = data.meta.total;
                this.hasMore = data.meta.has_more;
                this.isFetching = false;
                this.removeScrollListener();
                this.buildSidebarLinks();
                this.attachScrollListener();
              } catch {
                this.isFetching = false;
              }
            }

            loadMore() {
              if (this.isFetching || !this.hasMore) {
                return;
              }

              this.page = this.page + 1;
              this.fetchMessages(true);
            }

            groupByDate(topic) {
              const now = new Date();
              const lastPostedAt = new Date(topic.last_posted_at);
              const daysDiff = Math.round(
                (now - lastPostedAt) / (1000 * 60 * 60 * 24)
              );

              if (daysDiff <= 1 || !topic.last_posted_at) {
                if (!this.loadedTodayLabel) {
                  this.loadedTodayLabel = true;
                  return {
                    text: i18n("discourse_ai.ai_bot.conversations.today"),
                    classNames: "date-heading",
                    name: "date-heading-today",
                  };
                }
              }
              // Last 7 days group
              else if (daysDiff <= 7) {
                if (!this.loadedSevenDayLabel) {
                  this.loadedSevenDayLabel = true;
                  return {
                    text: i18n("discourse_ai.ai_bot.conversations.last_7_days"),
                    classNames: "date-heading",
                    name: "date-heading-last-7-days",
                  };
                }
              }
              // Last 30 days group
              else if (daysDiff <= 30) {
                if (!this.loadedThirtyDayLabel) {
                  this.loadedThirtyDayLabel = true;
                  return {
                    text: i18n(
                      "discourse_ai.ai_bot.conversations.last_30_days"
                    ),
                    classNames: "date-heading",
                    name: "date-heading-last-30-days",
                  };
                }
              }
              // Group by month for older conversations
              else {
                const month = lastPostedAt.getMonth();
                const year = lastPostedAt.getFullYear();
                const monthKey = `${year}-${month}`;

                if (!this.loadedMonthLabels.has(monthKey)) {
                  this.loadedMonthLabels.add(monthKey);

                  const formattedDate = autoUpdatingRelativeAge(
                    new Date(topic.last_posted_at)
                  );

                  return {
                    text: htmlSafe(formattedDate),
                    classNames: "date-heading",
                    name: `date-heading-${monthKey}`,
                  };
                }
              }
            }

            buildSidebarLinks() {
              // Reset date header tracking
              this.loadedTodayLabel = false;
              this.loadedSevenDayLabel = false;
              this.loadedThirtyDayLabel = false;
              this.loadedMonthLabels.clear();

              this.links = [...this.topics].flatMap((topic) => {
                const dateLabel = this.groupByDate(topic);
                return dateLabel
                  ? [dateLabel, new AiConversationLink(topic)]
                  : [new AiConversationLink(topic)];
              });
            }

            watchForTitleUpdate(topic) {
              const channel = `/discourse-ai/ai-bot/topic/${topic.id}`;
              const callback = this.updateTopicTitle.bind(this);
              messageBus.subscribe(channel, ({ title }) => {
                callback(topic, title);
                messageBus.unsubscribe(channel);
              });
            }

            updateTopicTitle(topic, title) {
              // update the data
              topic.title = title;

              // force Glimmer to re-render that one link
              this.links = this.links.map((link) =>
                link?.topic?.id === topic.id
                  ? new AiConversationLink(topic)
                  : link
              );
            }
          };
        },
        AI_CONVERSATIONS_PANEL
      );

      const setSidebarPanel = (transition) => {
        if (transition?.to?.name === "discourse-ai-bot-conversations") {
          return aiConversationsSidebarManager.forceCustomSidebar();
        }

        const topic = api.container.lookup("controller:topic").model;
        // if the topic is not a private message, not created by the current user,
        // or doesn't have a bot response, we don't need to override sidebar
        if (
          topic?.archetype === "private_message" &&
          topic.user_id === currentUser.id &&
          topic.is_bot_pm
        ) {
          return aiConversationsSidebarManager.forceCustomSidebar();
        }

        // newTopicForceSidebar is set to true when a new topic is created. We have
        // this because the condition `postStream.posts` above will not be true as the bot response
        // is not in the postStream yet when this initializer is ran. So we need to force
        // the sidebar to open when creating a new topic. After that, we set it to false again.
        if (aiConversationsSidebarManager.newTopicForceSidebar) {
          aiConversationsSidebarManager.newTopicForceSidebar = false;
          return aiConversationsSidebarManager.forceCustomSidebar();
        }

        aiConversationsSidebarManager.stopForcingCustomSidebar();
      };

      api.container
        .lookup("service:router")
        .on("routeDidChange", setSidebarPanel);
    });
  },
};
