import { SearchOutlined, PlusOutlined } from "@ant-design/icons";
import { Button, Input, Spin } from "antd";
import { t } from "i18next";
import { useEffect, useMemo, useRef, useState } from "react";
import { useNavigate, useParams } from "react-router-dom";
import { Virtuoso, VirtuosoHandle } from "react-virtuoso";

import FlexibleSider from "@/components/FlexibleSider";
import AddColleague from "@/pages/common/AddColleague";
import { useConversationStore, useUserStore } from "@/store";

import ConversationItemComp from "./ConversationItem";

const prefersReducedMotion = () =>
  typeof window !== "undefined" &&
  window.matchMedia("(prefers-reduced-motion: reduce)").matches;

const OfflineBar = ({ visible }: { visible: boolean }) => {
  const [shown, setShown] = useState(visible);
  const [leaving, setLeaving] = useState(false);

  useEffect(() => {
    if (visible) {
      setShown(true);
      setLeaving(false);
      return;
    }
    if (!shown) return;
    if (prefersReducedMotion()) {
      setShown(false);
      setLeaving(false);
      return;
    }
    setLeaving(true);
    const timer = window.setTimeout(() => {
      setShown(false);
      setLeaving(false);
    }, 300);
    return () => window.clearTimeout(timer);
  }, [visible, shown]);

  if (!shown) return null;

  return (
    <div
      style={{
        overflow: "hidden",
        maxHeight: leaving ? 0 : 80,
        opacity: leaving ? 0 : 1,
        transition: leaving ? "max-height 300ms ease-out, opacity 300ms ease-out" : "none",
      }}
    >
      <div
        className="flex h-9 items-center px-4 text-sm text-white"
        style={{ backgroundColor: "var(--banner-bg)" }}
      >
        <svg
          width="16"
          height="16"
          viewBox="0 0 24 24"
          fill="none"
          className="mr-2 shrink-0"
        >
          <circle cx="12" cy="12" r="9" stroke="#fff" strokeWidth="1.8" />
          <path d="M12 7.5v5.5" stroke="#fff" strokeWidth="1.8" strokeLinecap="round" />
          <circle cx="12" cy="16.5" r="1.2" fill="#fff" />
        </svg>
        {t("states.offline")}
      </div>
      <div className="px-4 py-2 text-xs text-[var(--sub-text)]">
        {t("states.offlineTip")}
      </div>
    </div>
  );
};

const LinearChatIcon = () => (
  <svg width="64" height="64" viewBox="0 0 24 24" fill="none">
    <path
      d="M5 6.5h14a1.5 1.5 0 0 1 1.5 1.5v8a1.5 1.5 0 0 1-1.5 1.5h-7.2L7 20.5v-2.5H5A1.5 1.5 0 0 1 3.5 16V8A1.5 1.5 0 0 1 5 6.5Z"
      stroke="var(--gap-text)"
      strokeWidth="1.6"
      strokeLinejoin="round"
    />
  </svg>
);

const LinearFailIcon = () => (
  <svg width="64" height="64" viewBox="0 0 24 24" fill="none">
    <path
      d="M5 6.5h14a1.5 1.5 0 0 1 1.5 1.5v8a1.5 1.5 0 0 1-1.5 1.5h-7.2L7 20.5v-2.5H5A1.5 1.5 0 0 1 3.5 16V8A1.5 1.5 0 0 1 5 6.5Z"
      stroke="var(--gap-text)"
      strokeWidth="1.6"
      strokeLinejoin="round"
    />
    <path d="M12 9v3.5" stroke="var(--warn-text)" strokeWidth="1.8" strokeLinecap="round" />
    <circle cx="12" cy="15.2" r="1" fill="var(--warn-text)" />
  </svg>
);

const ConversationSider = () => {
  const { conversationID } = useParams();
  const navigate = useNavigate();
  const conversationList = useConversationStore((state) => state.conversationList);
  const getConversationListByReq = useConversationStore(
    (state) => state.getConversationListByReq,
  );
  const syncState = useUserStore((state) => state.syncState);
  const connectState = useUserStore((state) => state.connectState);
  const [keyword, setKeyword] = useState("");
  const [addColleagueOpen, setAddColleagueOpen] = useState(false);
  const virtuoso = useRef<VirtuosoHandle>(null);
  const hasmore = useRef(true);
  const loading = useRef(false);

  const filteredList = useMemo(() => {
    const word = keyword.trim();
    if (!word) return conversationList;
    return conversationList.filter((conversation) =>
      conversation.showName?.toLowerCase().includes(word.toLowerCase()),
    );
  }, [conversationList, keyword]);

  const endReached = async () => {
    if (!hasmore.current || loading.current || keyword.trim()) return;
    loading.current = true;
    hasmore.current = await getConversationListByReq(true);
    loading.current = false;
  };

  const renderBody = () => {
    if (syncState === "loading" && conversationList.length === 0) {
      return (
        <div className="flex flex-1 flex-col items-center justify-center">
          <Spin />
          <div className="mt-4 text-sm">{t("states.loading")}</div>
          <div className="mt-1 text-xs text-[var(--sub-text)]">
            {t("states.loadingTip")}
          </div>
        </div>
      );
    }
    if (syncState === "failed" && conversationList.length === 0) {
      return (
        <div className="flex flex-1 flex-col items-center justify-center">
          <LinearFailIcon />
          <div className="mt-4 text-sm">{t("states.loadFailed")}</div>
          <div className="mt-1 text-xs text-[var(--sub-text)]">
            {t("states.loadFailedTip")}
          </div>
          <Button className="mt-4" onClick={() => getConversationListByReq(false)}>
            {t("retry")}
          </Button>
        </div>
      );
    }
    if (conversationList.length === 0) {
      return (
        <div className="flex flex-1 flex-col items-center justify-center">
          <LinearChatIcon />
          <div className="mt-4 text-sm">{t("states.noMessage")}</div>
          <div className="mt-1 text-xs text-[var(--sub-text)]">
            {t("states.noMessageTip")}
          </div>
          <Button
            className="mt-4"
            type="primary"
            onClick={() => navigate("/contact")}
          >
            {t("states.findColleague")}
          </Button>
        </div>
      );
    }
    return (
      <Virtuoso
        className="flex-1"
        data={filteredList}
        ref={virtuoso}
        endReached={endReached}
        computeItemKey={(_, item) => item.conversationID}
        itemContent={(_, conversation) => (
          <ConversationItemComp
            isActive={conversationID === conversation.conversationID}
            conversation={conversation}
          />
        )}
      />
    );
  };

  return (
    <FlexibleSider
      needHidden={Boolean(conversationID)}
      wrapClassName="flex flex-col border-r border-[var(--gap-text)] bg-white"
    >
      <OfflineBar visible={connectState === "failed"} />
      <div className="app-drag px-4 pt-4">
        <div className="pb-3 text-base font-bold">{t("placeholder.chat")}</div>
        <div className="flex items-center gap-1.5">
          <Input
            className="app-no-drag mb-2 rounded-md border-none bg-[var(--search-bg)]"
            style={{ height: 36, backgroundColor: "var(--search-bg)" }}
            prefix={<SearchOutlined className="text-[var(--sub-text)]" rev={undefined} />}
            placeholder={t("placeholder.search")}
            allowClear
            value={keyword}
            onChange={(e) => setKeyword(e.target.value)}
          />
          <div
            className="app-no-drag flex h-9 w-9 shrink-0 cursor-pointer items-center justify-center rounded-lg text-[20px] text-[var(--sub-text)] transition-colors duration-100 ease-out hover:bg-[var(--primary-active)] hover:text-[var(--primary)]"
            title={t("placeholder.addColleague")}
            onClick={() => setAddColleagueOpen(true)}
          >
            <PlusOutlined rev={undefined} />
          </div>
        </div>
      </div>
      {renderBody()}
      <AddColleague open={addColleagueOpen} onClose={() => setAddColleagueOpen(false)} />
    </FlexibleSider>
  );
};

export default ConversationSider;
