import { request } from "../../../utils/request";
import { shopId } from "../../../env";
import {
  join,
  leave,
  addCustomEventListener,
  removeCustomEventListener,
} from "../../../utils/server-sent-events";

type CommentMessage = {
  id: string;
  name: string;
  msg: string;
  kind?: "system" | "chat";
};

type CommentFeatureState = {
  approved: boolean;
  unreadReminder: boolean;
  optimizedInput: boolean;
  topTicker: boolean;
};

interface CommentProperties {
  enhancementApproved: boolean;
  avatarUrl: string;
}

interface CommentData {
  list: CommentMessage[];
  displayList: CommentMessage[];
  scrollTop: number;
  isAtBottom: boolean;
  maxVisible: number;
  itemHeight: number;
  MAX_HISTORY: number;
  joined: boolean;
  listener: boolean;
  lastMsgKey: string;
  inputValue: string;
  canSubmit: boolean;
  inputFocused: boolean;
  inputPlaceholderStyle: string;
  showGuidePopup: boolean;
  guideTitle: string;
  guideSubtitle: string;
  guideImages: string[];
  heartParticles: any[];
  heartButtonActive: boolean;
  unreadMessageCount: number;
  topNoticeText: string;
  topNoticeVisible: boolean;
  featureState: CommentFeatureState;
}

interface CommentInstance extends WechatMiniprogram.Component.TrivialInstance {
  data: CommentData;
  properties: CommentProperties;
  _sseListener?: (payload: any) => void;
  _heartButtonTimer?: number | null;
  _heartTimers?: number[];
  _topNoticeTimer?: number | null;
  _topNoticeQueue?: string[];
  safeLeave: () => Promise<void>;
  bindSseListener: () => void;
  unbindSseListener: () => void;
  appendMsgFromSse: (
    payload: { name: string; msg: string },
    options?: { kind?: "system" | "chat"; skipTopNotice?: boolean },
  ) => void;
  handleSubmit: (e: any) => Promise<void>;
  appendMsgText: (text: string) => void;
  createHeartParticle: (index: number) => any;
  removeHeartParticle: (id: string) => void;
  clearHeartEffects: () => void;
  safeVibrate: () => void;
}

const ITEM_HEIGHT = 60;
const MAX_VISIBLE = 5;
const MAX_HISTORY = 50;
const SSE_CHANNEL = "12";
const SYSTEM_NOTICE = "欢迎来到直播间，请文明发言，禁止发布违规信息。";
const DEFAULT_GUIDE_SUBTITLE = "个人中心";
const DEFAULT_GUIDE_IMAGES = Object.freeze(["/assets/img/600.jpg"]);
const DEFAULT_PLACEHOLDER_STYLE = "color:white;font-size:32rpx";
const ENHANCED_PLACEHOLDER_STYLE =
  "color:rgba(255,255,255,0.62);font-size:28rpx";
const TOP_NOTICE_DURATION = 3400;
const REVIEW_READY_FEATURES = Object.freeze({
  unreadReminder: true,
  optimizedInput: true,
  topTicker: true,
});

function getChatChannelName() {
  return `${shopId}-${SSE_CHANNEL}`;
}

function createMessage(
  name: string,
  msg: string,
  kind: "system" | "chat" = "chat",
): CommentMessage {
  return {
    id: `msg_${Date.now()}_${Math.floor(Math.random() * 1000)}`,
    name,
    msg,
    kind,
  };
}

function buildWelcomeMessage() {
  return createMessage("系统", SYSTEM_NOTICE, "system");
}

function buildFeatureState(approved: boolean): CommentFeatureState {
  return {
    approved,
    unreadReminder: approved && REVIEW_READY_FEATURES.unreadReminder,
    optimizedInput: approved && REVIEW_READY_FEATURES.optimizedInput,
    topTicker: approved && REVIEW_READY_FEATURES.topTicker,
  };
}

function sanitizeInput(value: unknown): string {
  return String(value ?? "")
    .replace(/\s+/g, " ")
    .trim();
}

function buildGuideImages(avatarUrl: unknown): string[] {
  const normalizedAvatarUrl = sanitizeInput(avatarUrl);

  return normalizedAvatarUrl
    ? [normalizedAvatarUrl]
    : [...DEFAULT_GUIDE_IMAGES];
}

function syncGuideImages(instance: CommentInstance, avatarUrl: unknown) {
  const nextGuideImages = buildGuideImages(avatarUrl);
  const currentGuideImages = instance.data.guideImages || [];
  const unchanged =
    currentGuideImages.length === nextGuideImages.length &&
    currentGuideImages.every((item, index) => item === nextGuideImages[index]);

  if (unchanged) return;

  instance.setData({
    guideImages: nextGuideImages,
  });
}

function trimMessages(messages: CommentMessage[], maxHistory: number) {
  if (messages.length <= maxHistory) return messages;

  const pinnedMessage = messages[0]?.kind === "system" ? messages[0] : null;
  if (!pinnedMessage) {
    return messages.slice(-maxHistory);
  }

  const normalMessages = messages.slice(1);
  return [pinnedMessage, ...normalMessages.slice(-(maxHistory - 1))];
}

function formatTopNoticeText(name: string, msg: string) {
  const safeName = sanitizeInput(name) || "新消息";
  const preview = sanitizeInput(msg);
  const clippedPreview =
    preview.length > 18 ? `${preview.slice(0, 18)}...` : preview;

  return clippedPreview
    ? `${safeName}：${clippedPreview}`
    : `${safeName} 发来了一条新消息`;
}

function clearTopNotice(instance: CommentInstance) {
  if (instance._topNoticeTimer) {
    clearTimeout(instance._topNoticeTimer);
    instance._topNoticeTimer = null;
  }

  instance._topNoticeQueue = [];

  if (instance.data.topNoticeVisible || instance.data.topNoticeText) {
    instance.setData({
      topNoticeVisible: false,
      topNoticeText: "",
    });
  }
}

function playTopNoticeQueue(instance: CommentInstance) {
  if (!instance.data.featureState.topTicker || instance.data.topNoticeVisible) {
    return;
  }

  instance._topNoticeQueue = instance._topNoticeQueue || [];
  const nextNotice = instance._topNoticeQueue.shift();
  if (!nextNotice) return;

  instance.setData(
    {
      topNoticeText: nextNotice,
      topNoticeVisible: false,
    },
    () => {
      wx.nextTick(() => {
        instance.setData({ topNoticeVisible: true });
        instance._topNoticeTimer = setTimeout(() => {
          instance.setData({ topNoticeVisible: false }, () => {
            instance._topNoticeTimer = null;
            playTopNoticeQueue(instance);
          });
        }, TOP_NOTICE_DURATION);
      });
    },
  );
}

function enqueueTopNotice(instance: CommentInstance, text: string) {
  if (!instance.data.featureState.topTicker || !text) return;

  instance._topNoticeQueue = instance._topNoticeQueue || [];
  instance._topNoticeQueue.push(text);

  if (!instance.data.topNoticeVisible) {
    playTopNoticeQueue(instance);
  }
}

function clearUnreadReminder(instance: CommentInstance) {
  if (!instance.data.unreadMessageCount) return;

  instance.setData({ unreadMessageCount: 0 });
}

function scrollToLatest(instance: CommentInstance, clearUnread = false) {
  if (clearUnread) {
    clearUnreadReminder(instance);
  }

  instance.setData({ scrollTop: Date.now() });
}

function syncFeatureApproval(instance: CommentInstance, approved: boolean) {
  const justEnabledTopTicker =
    !instance.data.featureState.topTicker &&
    approved &&
    REVIEW_READY_FEATURES.topTicker;
  const featureState = buildFeatureState(approved);

  instance.setData(
    {
      featureState,
      inputPlaceholderStyle: featureState.optimizedInput
        ? ENHANCED_PLACEHOLDER_STYLE
        : DEFAULT_PLACEHOLDER_STYLE,
      inputFocused: featureState.optimizedInput
        ? instance.data.inputFocused
        : false,
      unreadMessageCount: featureState.unreadReminder
        ? instance.data.unreadMessageCount
        : 0,
      topNoticeText: featureState.topTicker ? instance.data.topNoticeText : "",
      topNoticeVisible: featureState.topTicker
        ? instance.data.topNoticeVisible
        : false,
    },
    () => {
      if (justEnabledTopTicker) {
        enqueueTopNotice(
          instance,
          formatTopNoticeText("直播提醒", SYSTEM_NOTICE),
        );
      }
    },
  );

  if (!featureState.topTicker) {
    clearTopNotice(instance);
  }
}

Component({
  properties: {
    enhancementApproved: {
      type: Boolean,
      value: false,
      observer(this: CommentInstance, nextValue: boolean) {
        syncFeatureApproval(this, !!nextValue);
      },
    },
    avatarUrl: {
      type: String,
      value: "",
      observer(this: CommentInstance, nextValue: string) {
        syncGuideImages(this, nextValue);
      },
    },
  },

  data: {
    list: [] as CommentMessage[],
    displayList: [] as CommentMessage[],
    scrollTop: 999999,
    isAtBottom: true,
    maxVisible: MAX_VISIBLE,
    itemHeight: ITEM_HEIGHT,
    MAX_HISTORY,
    joined: false,
    listener: false,
    lastMsgKey: "",
    inputValue: "",
    canSubmit: false,
    inputFocused: false,
    inputPlaceholderStyle: DEFAULT_PLACEHOLDER_STYLE,
    showGuidePopup: false,
    guideTitle: "",
    guideSubtitle: DEFAULT_GUIDE_SUBTITLE,
    guideImages: [...DEFAULT_GUIDE_IMAGES],
    heartParticles: [] as any[],
    heartButtonActive: false,
    unreadMessageCount: 0,
    topNoticeText: "",
    topNoticeVisible: false,
    featureState: buildFeatureState(false),
  } as CommentData,

  lifetimes: {
    attached(this: CommentInstance) {
      const initialMessages = [buildWelcomeMessage()];
      this._topNoticeQueue = [];

      this.setData(
        {
          list: initialMessages,
          displayList: initialMessages,
        },
        () => {
          syncGuideImages(this, this.properties.avatarUrl);
          syncFeatureApproval(this, !!this.properties.enhancementApproved);
          this.bindSseListener();

          setTimeout(() => {
            scrollToLatest(this);
          }, 50);
        },
      );
    },

    detached(this: CommentInstance) {
      this.unbindSseListener();
      this.safeLeave();
      this.clearHeartEffects();
      clearTopNotice(this);
    },
  },

  pageLifetimes: {
    show(this: CommentInstance) {
      this.bindSseListener();

      wx.nextTick(async () => {
        if (this.data.joined) return;

        try {
          await join(getChatChannelName());
          this.setData({ joined: true });
        } catch (error) {
          console.warn("SSE join failed", error);
        }
      });
    },

    hide(this: CommentInstance) {
      this.unbindSseListener();
      this.safeLeave();
      this.clearHeartEffects();
      clearTopNotice(this);
    },
  },

  methods: {
    async safeLeave(this: CommentInstance) {
      if (!this.data.joined) return;

      this.setData({ joined: false });
      try {
        await leave(getChatChannelName());
      } catch (error) {
        console.warn("SSE leave failed", error);
      }
    },

    bindSseListener(this: CommentInstance) {
      if (this.data.listener) return;

      this.setData({ listener: true });

      this._sseListener = (payload: any) => {
        if (!payload) return;

        const { name, msg } = payload;
        if (!msg && msg !== "") return;

        const key = `${name ?? ""}:${msg}`;
        if (key === this.data.lastMsgKey) return;

        this.setData({ lastMsgKey: key });
        this.appendMsgFromSse({
          name: name ?? "用户",
          msg,
        });
      };

      addCustomEventListener("pushMsg", this._sseListener);
    },

    unbindSseListener(this: CommentInstance) {
      if (!this.data.listener) return;

      this.setData({ listener: false });

      if (!this._sseListener) return;

      removeCustomEventListener("pushMsg", this._sseListener);
      this._sseListener = undefined;
    },

    onScroll(this: CommentInstance, e: any) {
      const { scrollTop, scrollHeight } = e.detail;

      wx.createSelectorQuery()
        .in(this)
        .select("#scrollView")
        .boundingClientRect((rect) => {
          const clientHeight = rect?.height || 0;
          const isBottom = scrollTop + clientHeight >= scrollHeight - 20;
          if (isBottom !== this.data.isAtBottom) {
            this.setData({ isAtBottom: isBottom });
          }

          if (isBottom) {
            clearUnreadReminder(this);
          }
        })
        .exec();
    },

    appendMsgFromSse(
      this: CommentInstance,
      payload: { name: string; msg: string },
      options: { kind?: "system" | "chat"; skipTopNotice?: boolean } = {},
    ) {
      const messageName =
        sanitizeInput(payload.name) ||
        (options.kind === "system" ? "系统" : "用户");
      const messageText = String(payload.msg ?? "");
      const nextMessage = createMessage(
        messageName,
        messageText,
        options.kind || "chat",
      );
      const nextList = trimMessages(
        [...this.data.list, nextMessage],
        this.data.MAX_HISTORY,
      );
      const shouldAutoScroll = this.data.isAtBottom;
      const shouldShowUnreadReminder =
        this.data.featureState.unreadReminder &&
        !shouldAutoScroll &&
        (options.kind || "chat") !== "system";

      this.setData(
        {
          list: nextList,
          displayList: nextList,
          unreadMessageCount: shouldShowUnreadReminder
            ? this.data.unreadMessageCount + 1
            : this.data.unreadMessageCount,
        },
        () => {
          if (shouldAutoScroll) {
            scrollToLatest(this);
          }
        },
      );

      if (this.data.featureState.topTicker && !options.skipTopNotice) {
        enqueueTopNotice(this, formatTopNoticeText(messageName, messageText));
      }
    },

    handleInput(this: CommentInstance, e: any) {
      const value = e.detail.value || "";

      this.setData({
        inputValue: value,
        canSubmit: !!sanitizeInput(value),
      });
    },

    handleInputFocus(this: CommentInstance) {
      if (!this.data.featureState.optimizedInput) return;

      this.setData({ inputFocused: true });
    },

    handleInputBlur(this: CommentInstance) {
      if (!this.data.inputFocused) return;

      this.setData({ inputFocused: false });
    },

    submitCurrentInput(this: CommentInstance) {
      if (!this.data.canSubmit) return;

      this.handleSubmit({
        detail: {
          value: this.data.inputValue,
        },
      });
    },

    handleUnreadReminderTap(this: CommentInstance) {
      scrollToLatest(this, true);
    },

    openGuidePopup(this: CommentInstance) {
      this.setData({
        showGuidePopup: true,
        guideTitle: wx.getStorageSync("userName") || "当前用户",
        guideSubtitle: DEFAULT_GUIDE_SUBTITLE,
      });
    },

    closeGuidePopup(this: CommentInstance) {
      this.setData({
        showGuidePopup: false,
      });
    },

    async handleSubmit(this: CommentInstance, e: any) {
      const value = sanitizeInput(e?.detail?.value ?? this.data.inputValue);

      if (!value) {
        wx.showToast({
          title: "发送内容不能为空",
          icon: "none",
          duration: 2000,
        });
        return;
      }

      try {
        await request({
          options: {
            url: "/app/mini-app/push-chat-msg",
            data: {
              shopId,
              id: Number(SSE_CHANNEL),
              name: wx.getStorageSync("userName") || "微信用户",
              msg: value,
            },
          },
          isLoading: false,
        });
      } catch (error) {
        console.log(error, "push chat message failed");
        this.appendMsgText(value);
      } finally {
        this.setData({
          inputValue: "",
          canSubmit: false,
        });
      }
    },

    appendMsgText(this: CommentInstance, text: string) {
      this.appendMsgFromSse({
        name: wx.getStorageSync("userName") || "微信用户",
        msg: text,
      });
    },

    handleHeartTap(this: CommentInstance) {
      const particles = Array.from({ length: 6 }, (_, index) =>
        this.createHeartParticle(index),
      );

      this.setData({
        heartParticles: [...this.data.heartParticles, ...particles],
        heartButtonActive: true,
      });

      this.safeVibrate();

      if (this._heartButtonTimer) {
        clearTimeout(this._heartButtonTimer);
      }

      this._heartButtonTimer = setTimeout(() => {
        this.setData({ heartButtonActive: false });
      }, 220);

      this._heartTimers = this._heartTimers || [];
      particles.forEach((particle: any) => {
        const timer = setTimeout(
          () => {
            this.removeHeartParticle(particle.id);
          },
          particle.duration + particle.delay + 260,
        );
        this._heartTimers?.push(timer);
      });
    },

    createHeartParticle(index: number) {
      const palette = ["#ff4d6d", "#ff6b81", "#ff8399", "#ffb3c1"];
      const pathClasses = ["path-left", "path-center", "path-right"];
      const pulseClasses = ["pulse-small", "pulse-medium", "pulse-large"];

      return {
        id: `heart_${Date.now()}_${index}_${Math.floor(Math.random() * 1000)}`,
        right: 16 + Math.floor(Math.random() * 28),
        bottom: 10 + Math.floor(Math.random() * 18),
        size: 34 + Math.floor(Math.random() * 10),
        color:
          palette[
            (index + Math.floor(Math.random() * palette.length)) %
              palette.length
          ],
        duration: 920 + Math.floor(Math.random() * 320),
        delay: index * 40,
        rotate: -16 + Math.floor(Math.random() * 32),
        pathClass:
          pathClasses[
            (index + Math.floor(Math.random() * pathClasses.length)) %
              pathClasses.length
          ],
        pulseClass: pulseClasses[index % pulseClasses.length],
      };
    },

    removeHeartParticle(this: CommentInstance, id: string) {
      this.setData({
        heartParticles: this.data.heartParticles.filter(
          (item: any) => item.id !== id,
        ),
      });
    },

    clearHeartEffects(this: CommentInstance) {
      if (this._heartButtonTimer) {
        clearTimeout(this._heartButtonTimer);
        this._heartButtonTimer = null;
      }

      if (Array.isArray(this._heartTimers)) {
        this._heartTimers.forEach((timer) => clearTimeout(timer));
        this._heartTimers = [];
      }

      this.setData({
        heartParticles: [],
        heartButtonActive: false,
      });
    },

    safeVibrate() {
      if (typeof wx.vibrateShort !== "function") return;

      try {
        wx.vibrateShort();
      } catch (error) {
        console.warn("vibrateShort failed", error);
      }
    },
  },
});
