"use client";

import { useEffect, useMemo, useRef, useState } from "react";
import { ChevronLeft, MessageCircleMore, Send, X } from "lucide-react";

import type { ChatConversation, ChatThread } from "@rental/shared";

import { getChatConversationRequest, getChatThreadsRequest, sendChatMessageRequest } from "../../lib/api";
import { cn } from "../../lib/cn";
import { useIsMobile } from "../../lib/use-is-mobile";
import { useSessionContext } from "./session-provider";
import { Badge } from "../ui/badge";
import { Button } from "../ui/button";
import { Input } from "../ui/input";

const POLL_MS = 5000;

const formatChatTimestamp = (value: string) =>
  new Intl.DateTimeFormat("pl-PL", {
    day: "2-digit",
    month: "2-digit",
    hour: "2-digit",
    minute: "2-digit"
  }).format(new Date(value));

export const ChatLauncher = () => {
  const { session } = useSessionContext();
  const isMobile = useIsMobile();
  const [open, setOpen] = useState(false);
  const [threads, setThreads] = useState<ChatThread[]>([]);
  const [selectedUserId, setSelectedUserId] = useState<string | null>(null);
  const [conversation, setConversation] = useState<ChatConversation | null>(null);
  const [draft, setDraft] = useState("");
  const [loadingThreads, setLoadingThreads] = useState(false);
  const [loadingConversation, setLoadingConversation] = useState(false);
  const [sending, setSending] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [animationTick, setAnimationTick] = useState(0);
  const previousUnreadRef = useRef(0);
  const messagesViewportRef = useRef<HTMLDivElement | null>(null);

  const totalUnread = useMemo(() => threads.reduce((sum, thread) => sum + thread.unreadCount, 0), [threads]);

  const selectedThread = useMemo(
    () => threads.find((thread) => thread.user.id === selectedUserId) ?? null,
    [selectedUserId, threads]
  );

  const syncThreads = async () => {
    if (!session) {
      return;
    }

    setLoadingThreads(true);

    try {
      const nextThreads = await getChatThreadsRequest(session);
      setThreads(nextThreads);
      setError(null);
      setSelectedUserId((current) => {
        if (current && nextThreads.some((thread) => thread.user.id === current)) {
          return current;
        }

        return nextThreads.find((thread) => thread.unreadCount > 0)?.user.id ?? nextThreads[0]?.user.id ?? null;
      });
    } catch (requestError) {
      setError(requestError instanceof Error ? requestError.message : "Nie udało się pobrać listy rozmów");
    } finally {
      setLoadingThreads(false);
    }
  };

  const syncConversation = async (userId: string) => {
    if (!session) {
      return;
    }

    setLoadingConversation(true);

    try {
      const nextConversation = await getChatConversationRequest(session, userId);
      setConversation(nextConversation);
      setError(null);
      await syncThreads();
    } catch (requestError) {
      setError(requestError instanceof Error ? requestError.message : "Nie udało się pobrać rozmowy");
    } finally {
      setLoadingConversation(false);
    }
  };

  useEffect(() => {
    if (!session) {
      return;
    }

    void syncThreads();
  }, [session]);

  useEffect(() => {
    if (!session) {
      return;
    }

    const interval = window.setInterval(() => {
      void syncThreads();

      if (open && selectedUserId) {
        void syncConversation(selectedUserId);
      }
    }, POLL_MS);

    return () => window.clearInterval(interval);
  }, [open, selectedUserId, session]);

  useEffect(() => {
    if (!open || !selectedUserId) {
      return;
    }

    void syncConversation(selectedUserId);
  }, [open, selectedUserId]);

  useEffect(() => {
    if (totalUnread > previousUnreadRef.current) {
      setAnimationTick((value) => value + 1);
    }

    previousUnreadRef.current = totalUnread;
  }, [totalUnread]);

  useEffect(() => {
    if (!messagesViewportRef.current) {
      return;
    }

    messagesViewportRef.current.scrollTop = messagesViewportRef.current.scrollHeight;
  }, [conversation?.messages.length, open, selectedUserId]);

  const sendMessage = async () => {
    if (!session || !selectedUserId || !draft.trim()) {
      return;
    }

    setSending(true);

    try {
      await sendChatMessageRequest(session, {
        recipientId: selectedUserId,
        body: draft
      });
      setDraft("");
      await syncConversation(selectedUserId);
    } catch (requestError) {
      setError(requestError instanceof Error ? requestError.message : "Nie udało się wysłać wiadomości");
    } finally {
      setSending(false);
    }
  };

  if (!session) {
    return null;
  }

  return (
    <>
      <div
        className={cn(
          "fixed z-[70]",
          isMobile ? "bottom-[calc(env(safe-area-inset-bottom,0px)+3.25rem)] right-3" : "bottom-4 right-4"
        )}
      >
        <button
          type="button"
          aria-label="Otwórz chat wewnętrzny"
          className={cn(
            "relative flex h-12 w-12 items-center justify-center rounded-full border border-line bg-white text-ink shadow-soft transition hover:border-accent/50",
            open && "border-accent bg-accent text-white"
          )}
          onClick={() => setOpen((value) => !value)}
        >
          <span
            key={animationTick}
            className={cn(totalUnread > 0 && "animate__animated animate__heartBeat animate__faster")}
          >
            <MessageCircleMore className="h-5 w-5" />
          </span>

          {totalUnread > 0 ? (
            <span className="absolute -right-1 -top-1 flex min-w-5 items-center justify-center rounded-full bg-[#ff5a1f] px-1.5 py-0.5 text-[10px] font-semibold text-white">
              {totalUnread > 99 ? "99+" : totalUnread}
            </span>
          ) : null}
        </button>
      </div>

      {open ? (
        <div
          className={cn(
            "fixed z-[69] overflow-hidden border border-line bg-[rgba(255,252,245,0.98)] shadow-soft backdrop-blur",
            isMobile ? "inset-x-2 bottom-[calc(env(safe-area-inset-bottom,0px)+6.2rem)] top-20 rounded-[20px]" : "bottom-20 right-4 h-[min(72vh,680px)] w-[min(780px,calc(100vw-2rem))] rounded-[22px]"
          )}
        >
          <div className="flex h-full min-h-0">
            <aside
              className={cn(
                "border-line bg-[#f8f3ea]",
                isMobile
                  ? selectedUserId
                    ? "hidden"
                    : "flex w-full flex-col border-r-0"
                  : "flex w-[280px] shrink-0 flex-col border-r"
              )}
            >
              <div className="flex items-center justify-between border-b border-line px-4 py-3">
                <div>
                  <p className="text-sm font-semibold text-ink">Chat zespołu</p>
                  <p className="text-xs text-muted">Aktywni użytkownicy systemu</p>
                </div>
                <Button className="h-8 w-8 rounded-full p-0" variant="ghost" onClick={() => setOpen(false)}>
                  <X className="h-4 w-4" />
                </Button>
              </div>

              <div className="min-h-0 flex-1 overflow-y-auto p-2">
                {loadingThreads && threads.length === 0 ? <div className="px-3 py-4 text-sm text-muted">Ładowanie rozmów...</div> : null}
                {threads.map((thread) => (
                  <button
                    key={thread.user.id}
                    type="button"
                    className={cn(
                      "mb-2 flex w-full flex-col rounded-xl border px-3 py-2.5 text-left transition",
                      selectedUserId === thread.user.id ? "border-accent bg-white" : "border-transparent bg-white/65 hover:border-accent/35"
                    )}
                    onClick={() => setSelectedUserId(thread.user.id)}
                  >
                    <div className="flex items-start justify-between gap-3">
                      <div className="min-w-0">
                        <p className="truncate text-sm font-semibold text-ink">{thread.user.name}</p>
                        <p className="text-[11px] uppercase tracking-[0.14em] text-muted">{thread.user.role}</p>
                      </div>
                      {thread.unreadCount > 0 ? <Badge tone="warning">{thread.unreadCount}</Badge> : null}
                    </div>
                    <p className="mt-2 line-clamp-2 text-xs text-muted">
                      {thread.lastMessage ? thread.lastMessage.body : "Brak wiadomości. Kliknij, aby zacząć rozmowę."}
                    </p>
                  </button>
                ))}
              </div>
            </aside>

            <section className={cn("flex min-h-0 flex-1 flex-col", isMobile && !selectedUserId && "hidden")}>
              <div className="flex items-center justify-between border-b border-line px-4 py-3">
                <div className="flex min-w-0 items-center gap-2">
                  {isMobile ? (
                    <Button
                      className="h-8 w-8 rounded-full p-0"
                      variant="ghost"
                      onClick={() => {
                        setSelectedUserId(null);
                        setConversation(null);
                      }}
                    >
                      <ChevronLeft className="h-4 w-4" />
                    </Button>
                  ) : null}
                  <div className="min-w-0">
                    <p className="truncate text-sm font-semibold text-ink">
                      {selectedThread?.user.name ?? conversation?.user.name ?? "Wybierz rozmowę"}
                    </p>
                    <p className="text-xs text-muted">
                      {selectedThread?.user.role ?? conversation?.user.role ?? "Chat wewnętrzny"}
                    </p>
                  </div>
                </div>

                {!isMobile ? (
                  <Button className="h-8 w-8 rounded-full p-0" variant="ghost" onClick={() => setOpen(false)}>
                    <X className="h-4 w-4" />
                  </Button>
                ) : null}
              </div>

              {error ? <div className="mx-4 mt-4 rounded-xl bg-[#f8d9d3] px-4 py-3 text-sm text-[#8d2f20]">{error}</div> : null}

              <div ref={messagesViewportRef} className="min-h-0 flex-1 overflow-y-auto px-4 py-4">
                {!selectedUserId ? (
                  <div className="flex h-full items-center justify-center text-sm text-muted">
                    Wybierz użytkownika z listy, aby otworzyć rozmowę.
                  </div>
                ) : loadingConversation && !conversation ? (
                  <div className="flex h-full items-center justify-center text-sm text-muted">Ładowanie rozmowy...</div>
                ) : (
                  <div className="space-y-3">
                    {conversation?.messages.length ? (
                      conversation.messages.map((message) => {
                        const own = message.senderId === session.user.id;

                        return (
                          <div key={message.id} className={cn("flex", own ? "justify-end" : "justify-start")}>
                            <div
                              className={cn(
                                "max-w-[82%] rounded-2xl px-3 py-2.5 text-sm",
                                own ? "bg-accent text-white" : "border border-line bg-white text-ink"
                              )}
                            >
                              <p className="whitespace-pre-wrap break-words">{message.body}</p>
                              <div className={cn("mt-1 text-[11px]", own ? "text-white/75" : "text-muted")}>
                                {message.senderName} • {formatChatTimestamp(message.createdAt)}
                              </div>
                            </div>
                          </div>
                        );
                      })
                    ) : (
                      <div className="flex h-full items-center justify-center text-sm text-muted">
                        Jeszcze nie ma wiadomości. Zacznij rozmowę z tym użytkownikiem.
                      </div>
                    )}
                  </div>
                )}
              </div>

              <div className="border-t border-line px-4 py-3">
                <div className="flex items-end gap-2">
                  <Input
                    placeholder={selectedUserId ? "Napisz wiadomość..." : "Wybierz rozmowę z lewej strony"}
                    value={draft}
                    disabled={!selectedUserId || sending}
                    onChange={(event) => setDraft(event.target.value)}
                    onKeyDown={(event) => {
                      if (event.key === "Enter" && !event.shiftKey) {
                        event.preventDefault();
                        void sendMessage();
                      }
                    }}
                  />
                  <Button className="h-11 w-11 shrink-0 rounded-full p-0" disabled={!selectedUserId || !draft.trim() || sending} onClick={() => void sendMessage()}>
                    <Send className="h-4 w-4" />
                  </Button>
                </div>
              </div>
            </section>
          </div>
        </div>
      ) : null}
    </>
  );
};
