"use client";

import { ChangeEvent, ClipboardEvent, useEffect, useMemo, useRef, useState } from "react";

type ChatAttachment = {
  name: string;
  meta: string;
  kind: "image" | "file";
  url?: string;
  storageKey?: string;
};

type ChatMessage = {
  id: string;
  user: string;
  time: string;
  content: string;
  file?: ChatAttachment;
};

type ChatResponse = {
  messages: ChatMessage[];
  onlineUsers: string[];
};

type PendingAttachment = {
  file: File;
  name: string;
  meta: string;
  kind: "image" | "file";
  previewUrl?: string;
};

function detectBrowser() {
  const ua = navigator.userAgent;

  if (ua.includes("Edg/")) return "Edge";
  if (ua.includes("Chrome/")) return "Chrome";
  if (ua.includes("Safari/") && !ua.includes("Chrome/")) return "Safari";
  if (ua.includes("Firefox/")) return "Firefox";
  return "Browser";
}

function detectDevice() {
  const ua = navigator.userAgent;

  if (/iPhone/i.test(ua)) return "iPhone";
  if (/Android/i.test(ua)) return "Android";
  if (/Macintosh|Mac OS X/i.test(ua)) return "MacBook";
  if (/Windows/i.test(ua)) return "Windows";
  return "Device";
}

function createLocalName() {
  const stored = window.localStorage.getItem("lan-chat-user");

  if (stored) {
    return stored;
  }

  const suffix = Math.random().toString(36).slice(2, 6).toUpperCase();
  const nextValue = `${detectDevice()}-${detectBrowser()}-${suffix}`;
  window.localStorage.setItem("lan-chat-user", nextValue);
  return nextValue;
}

function getAvatarSeed(name: string) {
  return name
    .split("-")
    .slice(0, 2)
    .join("")
    .slice(0, 2)
    .toUpperCase();
}

function formatFileMeta(file: File) {
  const sizeMb = file.size / (1024 * 1024);
  const size = sizeMb >= 1 ? `${sizeMb.toFixed(1)} MB` : `${Math.max(1, Math.round(file.size / 1024))} KB`;
  return `${size} · ${file.type || "application/octet-stream"}`;
}

const emojiList = ["😊", "😀", "👍", "🎉", "📎", "🔥", "✨", "✅"];

export default function ChatPage() {
  const [messages, setMessages] = useState<ChatMessage[]>([]);
  const [onlineUsers, setOnlineUsers] = useState<string[]>([]);
  const [draft, setDraft] = useState("");
  const [userName, setUserName] = useState("局域网设备");
  const [sending, setSending] = useState(false);
  const [emojiOpen, setEmojiOpen] = useState(false);
  const [error, setError] = useState("");
  const [attachments, setAttachments] = useState<PendingAttachment[]>([]);
  const [previewImage, setPreviewImage] = useState<ChatAttachment | null>(null);
  const [downloadedFiles, setDownloadedFiles] = useState<Record<string, boolean>>({});
  const messageListRef = useRef<HTMLElement | null>(null);
  const fileInputRef = useRef<HTMLInputElement | null>(null);

  const onlineUsersWithCurrent = useMemo(() => {
    if (!userName || userName === "局域网设备") {
      return onlineUsers;
    }

    return onlineUsers.includes(userName) ? onlineUsers : [userName, ...onlineUsers];
  }, [onlineUsers, userName]);

  useEffect(() => {
    document.body.classList.add("chat-body");
    setUserName(createLocalName());
    const storedDownloads = window.localStorage.getItem("lan-chat-downloaded-files");

    if (storedDownloads) {
      try {
        setDownloadedFiles(JSON.parse(storedDownloads) as Record<string, boolean>);
      } catch {
        window.localStorage.removeItem("lan-chat-downloaded-files");
      }
    }

    return () => {
      document.body.classList.remove("chat-body");
    };
  }, []);

  useEffect(() => {
    return () => {
      attachments.forEach((a) => { if (a.previewUrl) URL.revokeObjectURL(a.previewUrl); });
    };
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [attachments]);

  useEffect(() => {
    if (!userName || userName === "局域网设备") {
      return;
    }

    let cancelled = false;

    const loadChat = async () => {
      try {
        const response = await fetch(`/api/chat?user=${encodeURIComponent(userName)}`, { cache: "no-store" });

        if (!response.ok) {
          throw new Error("加载聊天记录失败");
        }

        const data = (await response.json()) as ChatResponse;

        if (cancelled) {
          return;
        }

        setOnlineUsers(data.onlineUsers);
        setMessages((current) => {
          const currentLastId = current.at(-1)?.id;
          const nextLastId = data.messages.at(-1)?.id;

          if (currentLastId !== nextLastId || current.length !== data.messages.length) {
            queueMicrotask(() => {
              messageListRef.current?.scrollTo({
                top: messageListRef.current.scrollHeight,
                behavior: "auto"
              });
            });
          }

          return data.messages;
        });
        setError("");
      } catch (loadError) {
        if (!cancelled) {
          setError(loadError instanceof Error ? loadError.message : "加载聊天记录失败");
        }
      }
    };

    void loadChat();
    const timer = window.setInterval(() => void loadChat(), 2500);

    return () => {
      cancelled = true;
      window.clearInterval(timer);
    };
  }, [userName]);

  useEffect(() => {
    if (!messages.length) {
      return;
    }

    messageListRef.current?.scrollTo({
      top: messageListRef.current.scrollHeight,
      behavior: "auto"
    });
  }, [messages.length]);

  const appendEmoji = (emoji: string) => {
    setDraft((current) => `${current}${emoji}`);
    setEmojiOpen(false);
  };

  const openFilePicker = () => {
    fileInputRef.current?.click();
  };

  const MAX_ATTACHMENTS = 5;

  const clearPendingAttachments = () => {
    attachments.forEach((a) => { if (a.previewUrl) URL.revokeObjectURL(a.previewUrl); });
    setAttachments([]);
  };

  const removeAttachment = (index: number) => {
    setAttachments((current) => {
      const item = current[index];
      if (item?.previewUrl) URL.revokeObjectURL(item.previewUrl);
      return current.filter((_, i) => i !== index);
    });
  };

  const handleClearHistory = async () => {
    if (sending) {
      return;
    }

    const confirmed = window.confirm("确认清理本地和服务器的历史聊天记录吗？");

    if (!confirmed) {
      return;
    }

    setSending(true);

    try {
      const response = await fetch("/api/chat", {
        method: "DELETE",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify({
          user: userName
        })
      });

      if (!response.ok) {
        throw new Error("清理聊天记录失败");
      }

      const data = (await response.json()) as ChatResponse;
      setMessages(data.messages);
      setOnlineUsers(data.onlineUsers);
      setDraft("");
      clearPendingAttachments();
      setEmojiOpen(false);
      setPreviewImage(null);
      setError("");
      setDownloadedFiles({});
      window.localStorage.removeItem("lan-chat-downloaded-files");

      queueMicrotask(() => {
        messageListRef.current?.scrollTo({
          top: messageListRef.current.scrollHeight,
          behavior: "auto"
        });
      });
    } catch (clearError) {
      setError(clearError instanceof Error ? clearError.message : "清理聊天记录失败");
    } finally {
      setSending(false);
    }
  };

  const addFiles = (files: File[]) => {
    setAttachments((current) => {
      const remaining = MAX_ATTACHMENTS - current.length;
      if (remaining <= 0) return current;
      const toAdd = files.slice(0, remaining).map((file) => ({
        file,
        name: file.name,
        meta: formatFileMeta(file),
        kind: (file.type.startsWith("image/") ? "image" : "file") as "image" | "file",
        previewUrl: file.type.startsWith("image/") ? URL.createObjectURL(file) : undefined
      }));
      return [...current, ...toAdd];
    });
    setError("");
  };

  const handleFileChange = (event: ChangeEvent<HTMLInputElement>) => {
    const files = Array.from(event.target.files ?? []);
    if (files.length) addFiles(files);
    event.target.value = "";
  };

  const handlePaste = (event: ClipboardEvent<HTMLTextAreaElement>) => {
    const files = Array.from(event.clipboardData.items)
      .filter((item) => item.kind === "file")
      .map((item) => item.getAsFile())
      .filter((f): f is File => f !== null);

    if (!files.length) return;
    event.preventDefault();
    addFiles(files);
  };

  const handleSend = async () => {
    const content = draft.trim();

    if ((!content && attachments.length === 0) || sending) {
      return;
    }

    setSending(true);

    try {
      const newMessages: ChatMessage[] = [];
      let lastOnlineUsers: string[] = onlineUsers;

      // Send text first if any
      if (content) {
        const response = await fetch("/api/chat", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ user: userName, content })
        });
        if (!response.ok) throw new Error("发送失败");
        const data = (await response.json()) as { message: ChatMessage; onlineUsers: string[] };
        newMessages.push(data.message);
        lastOnlineUsers = data.onlineUsers;
      }

      // Send each attachment as a separate message
      for (const att of attachments) {
        const formData = new FormData();
        formData.append("user", userName);
        formData.append("content", "");
        formData.append("file", att.file);
        const response = await fetch("/api/chat", { method: "POST", body: formData });
        if (!response.ok) throw new Error("文件发送失败");
        const data = (await response.json()) as { message: ChatMessage; onlineUsers: string[] };
        newMessages.push(data.message);
        lastOnlineUsers = data.onlineUsers;
      }

      setMessages((current) => [...current, ...newMessages]);
      setOnlineUsers(lastOnlineUsers);
      setDraft("");
      clearPendingAttachments();
      setEmojiOpen(false);
      setError("");

      queueMicrotask(() => {
        messageListRef.current?.scrollTo({
          top: messageListRef.current.scrollHeight,
          behavior: "smooth"
        });
      });
    } catch (sendError) {
      setError(sendError instanceof Error ? sendError.message : "发送失败");
    } finally {
      setSending(false);
    }
  };

  const markFileDownloaded = (key: string) => {
    setDownloadedFiles((current) => {
      const next = { ...current, [key]: true };
      window.localStorage.setItem("lan-chat-downloaded-files", JSON.stringify(next));
      return next;
    });
  };

  const handleFileOpen = (message: ChatMessage) => {
    if (!message.file?.url) {
      return;
    }

    const key = `${message.id}:${message.file.storageKey || message.file.name}`;

    if (downloadedFiles[key]) {
      window.open(message.file.url, "_blank", "noopener,noreferrer");
      return;
    }

    const link = document.createElement("a");
    link.href = `${message.file.url}?download=1`;
    link.download = message.file.name;
    link.click();
    markFileDownloaded(key);
  };

  return (
    <main className="page-shell chat-wechat-page">
      <section className="chat-wechat-shell">
        <aside className="chat-wechat-sidebar" aria-label="在线用户">
          <div className="chat-wechat-sidebar__title">局域网在线设备</div>
          <div className="chat-wechat-sidebar__meta">{onlineUsersWithCurrent.length} 台设备在线</div>

          <div className="chat-wechat-member-list">
            {onlineUsersWithCurrent.map((name) => (
              <div key={name} className={`chat-wechat-member${name === userName ? " chat-wechat-member--self" : ""}`}>
                <div className="chat-wechat-member__avatar">{getAvatarSeed(name)}</div>
                <div className="chat-wechat-member__body">
                  <strong>{name}</strong>
                  <span>{name === userName ? "当前设备" : "局域网已连接"}</span>
                </div>
              </div>
            ))}
          </div>
        </aside>

        <section className="chat-wechat-main">
          <header className="chat-wechat-header">
            <div className="chat-wechat-header__row">
              <div className="chat-wechat-header__main">
                <div className="chat-wechat-header__title">局域网公共聊天室</div>
                <div className="chat-wechat-header__meta">文字、图片、文件都可以直接在这里流转</div>
              </div>

              <div className="chat-wechat-status" aria-label="在线状态">
                <span className="chat-wechat-status__text">{onlineUsersWithCurrent.length} 台设备在线</span>
                <span className="chat-wechat-status__icon" aria-hidden="true">
                  LAN
                </span>
              </div>
            </div>

            <div className="chat-wechat-header__presence">
              <div className="chat-wechat-header__avatars" aria-hidden="true">
                {onlineUsersWithCurrent.slice(0, 4).map((name) => (
                  <span key={name} className="chat-wechat-header__avatar">
                    {getAvatarSeed(name)}
                  </span>
                ))}
              </div>
              <div className="chat-wechat-header__presence-text">{onlineUsersWithCurrent.length} 台设备在线</div>
            </div>
          </header>

          <section className="chat-wechat-messages" aria-label="聊天消息列表" ref={messageListRef}>
            {messages.length === 0 ? <div className="chat-wechat-empty">聊天室已经准备好，现在发第一条消息吧。</div> : null}

            {messages.map((message) => {
              const self = message.user === userName;
              const imageAttachment = message.file?.kind === "image" ? message.file : null;

              return (
                <article key={message.id} className={`chat-wechat-message${self ? " chat-wechat-message--self" : ""}`}>
                  {!self ? <div className="chat-wechat-avatar">{getAvatarSeed(message.user)}</div> : null}

                  <div
                    className={`chat-wechat-message__body${
                      imageAttachment && !message.content ? " chat-wechat-message__body--image" : ""
                    }`}
                  >
                    {!self ? <div className="chat-wechat-message__name">{message.user}</div> : null}

                    <div
                      className={`chat-wechat-bubble${imageAttachment ? " chat-wechat-bubble--image" : ""}${
                        !message.content && message.file ? " chat-wechat-bubble--attachment-only" : ""
                      }`}
                    >
                      {message.content ? <div className="chat-wechat-bubble__text">{message.content}</div> : null}

                      {message.file ? (
                        <div
                          className={`chat-wechat-file${imageAttachment ? " chat-wechat-file--image" : ""}${
                            !imageAttachment ? " chat-wechat-file--download" : ""
                          }`}
                        >
                          {imageAttachment?.url ? (
                            <button
                              type="button"
                              className="chat-wechat-file__image-button"
                              onClick={() => setPreviewImage(imageAttachment)}
                            >
                              <img src={imageAttachment.url} alt={message.file.name} className="chat-wechat-file__image" />
                            </button>
                          ) : null}

                          {imageAttachment ? (
                            <button
                              type="button"
                              className="chat-wechat-file__link chat-wechat-file__link--image"
                              onClick={() => setPreviewImage(imageAttachment)}
                            >
                              <strong>{message.file.name}</strong>
                            </button>
                          ) : message.file.url ? (
                            <button type="button" className="chat-wechat-file__download" onClick={() => handleFileOpen(message)}>
                              <span className="chat-wechat-file__icon" aria-hidden="true">
                                文
                              </span>
                              <span className="chat-wechat-file__info">
                                <strong>{message.file.name}</strong>
                                <span>
                                  {downloadedFiles[`${message.id}:${message.file.storageKey || message.file.name}`]
                                    ? "点击打开"
                                    : "点击下载"}
                                </span>
                              </span>
                            </button>
                          ) : (
                            <strong>{message.file.name}</strong>
                          )}
                          <div className="chat-wechat-file__meta">{message.file.meta}</div>
                        </div>
                      ) : null}
                    </div>

                    <div className="chat-wechat-message__time">{message.time}</div>
                  </div>

                  {self ? <div className="chat-wechat-avatar chat-wechat-avatar--self">我</div> : null}
                </article>
              );
            })}
          </section>

          <footer className="chat-wechat-composer">
            <input
              ref={fileInputRef}
              type="file"
              hidden
              multiple
              accept="image/*,.pdf,.doc,.docx,.xls,.xlsx,.txt,.zip,.rar"
              onChange={handleFileChange}
            />

            <div className="chat-wechat-composer__tools">
              <div className="chat-wechat-tools-left">
                <button
                  className={`chat-wechat-tool${emojiOpen ? " is-active" : ""}`}
                  type="button"
                  aria-label="表情"
                  onClick={() => setEmojiOpen((current) => !current)}
                >
                  😊
                </button>
                <button className="chat-wechat-tool" type="button" aria-label="选择文件" onClick={openFilePicker}>
                  <svg className="chat-wechat-tool__icon" viewBox="0 0 24 24" aria-hidden="true">
                    <path d="M12 5v14M5 12h14" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
                  </svg>
                </button>
                <button
                  className="chat-wechat-tool chat-wechat-tool--danger"
                  type="button"
                  aria-label="清理聊天记录"
                  title="清理聊天记录"
                  onClick={() => void handleClearHistory()}
                >
                  清
                </button>
              </div>

              {error ? <div className="chat-wechat-error">{error}</div> : null}
            </div>

            {emojiOpen ? (
              <div className="chat-wechat-emoji-panel" aria-label="表情面板">
                {emojiList.map((emoji) => (
                  <button key={emoji} type="button" onClick={() => appendEmoji(emoji)}>
                    {emoji}
                  </button>
                ))}
              </div>
            ) : null}

            {attachments.length > 0 ? (
              <div className="chat-wechat-attachments">
                {attachments.map((att, index) => (
                  <div key={index} className="chat-wechat-attachment">
                    {att.kind === "image" && att.previewUrl ? (
                      <img src={att.previewUrl} alt={att.name} className="chat-wechat-attachment__image" />
                    ) : (
                      <span className="chat-wechat-attachment__icon">文</span>
                    )}
                    <div className="chat-wechat-attachment__meta">
                      <strong>{att.name}</strong>
                      <span>{att.meta}</span>
                    </div>
                    <button type="button" onClick={() => removeAttachment(index)} aria-label="移除附件">
                      ×
                    </button>
                  </div>
                ))}
                {attachments.length < MAX_ATTACHMENTS ? (
                  <button type="button" className="chat-wechat-attachment-add" onClick={openFilePicker} aria-label="继续添加">
                    +
                  </button>
                ) : null}
              </div>
            ) : null}

            <div className="chat-wechat-composer__row">
              <textarea
                className="chat-wechat-input"
                placeholder="输入消息，或直接粘贴图片 / 文件"
                value={draft}
                rows={1}
                onChange={(event) => setDraft(event.target.value)}
                onPaste={(event) => void handlePaste(event)}
                onKeyDown={(event) => {
                  if (event.key === "Enter" && !event.shiftKey) {
                    event.preventDefault();
                    void handleSend();
                  }
                }}
              />

              <button className="chat-wechat-send" type="button" onClick={() => void handleSend()} disabled={sending}>
                {sending ? "发送中" : attachments.length > 0 ? `发送(${attachments.length})` : "发送"}
              </button>
            </div>
          </footer>
        </section>
      </section>

      {previewImage?.url ? (
        <div className="chat-wechat-image-viewer" onClick={() => setPreviewImage(null)}>
          <img
            src={previewImage.url}
            alt={previewImage.name}
            className="chat-wechat-image-viewer__image"
            onClick={(event) => event.stopPropagation()}
          />
        </div>
      ) : null}
    </main>
  );
}
