"use client";

import { cn } from "~/lib/utils";
import {
  useCallback,
  useEffect,
  useRef,
  useState,
  type FormEvent,
} from "react";
import { api } from "~/utils/api";
import toast from "react-hot-toast";
import Input from "~/components/custom_ui/input";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
} from "~/components/ui/dialog";
import { Button } from "~/components/ui/button";
import { Pencil, Trash2 } from "lucide-react";
import type { MessagesMessageid } from "~/schemas/public/Messages";
import { AnimatePresence, motion } from "framer-motion";
import {
  ChatBubble,
  ChatBubbleAction,
  ChatBubbleActionWrapper,
  ChatBubbleMessage,
  ChatBubbleReadStatus,
  ChatBubbleTimestamp,
} from "~/components/chat/chat-bubble";
import { ChatMessageList } from "~/components/chat/chat-message-list";
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
} from "~/components/ui/alert-dialog";
import { useTranslation } from "~/providers/I18nProvider";
import type { ChatMessage } from "~/server/services/messages.service";
import type { UsersId } from "~/schemas/public/Users";
import type { WhoIsTyping } from "~/server/sse";
import type { Session } from "~/server/api/trpc";
import type { ChatsChatid } from "~/schemas/public/Chats";
import type { LiveChat } from "~/hooks/chatHooks";
import LoadingButton from "~/components/custom_ui/loading-button";
import { getUserColor, UserAvatar } from "~/components/user_avatar";

type ChatListProps = {
  chatId: ChatsChatid;
  messages: ChatMessage[];
  userData: Session;
  query: LiveChat["query"];
  typingStatus: WhoIsTyping[];
};

export const ChatList = ({
  chatId,
  messages,
  userData,
  query,
  typingStatus,
}: ChatListProps) => {
  const messagesContainerRef = useRef<HTMLDivElement>(null);
  const [editModalOpen, setEditModalOpen] = useState(false);
  const [msgSelected, setMsgSelected] = useState<ChatMessage | null>(null);
  const [deleteModalOpen, setDeleteModalOpen] = useState(false);

  const handleEditOpen = (status: boolean) => {
    setEditModalOpen(status);
  };
  const handleDeleteOpen = (status: boolean) => {
    setDeleteModalOpen(status);
  };

  const { mutate: deleteMutation } = api.messagesSSE.delete.useMutation({
    onMutate: () => {
      toast("Deleting message...", { icon: "🗑️", id: "deleteMessage" });
    },
    onSuccess: () => {
      toast("Message deleted", { icon: "🗑️", id: "deleteMessage" });
    },

    onError: () => {
      toast.error("Error deleting message", { id: "deleteMessage" });
    },
  });
  const { mutate: editMutation } = api.messagesSSE.edit.useMutation({
    onMutate: () => {
      toast("Editing message...", { icon: "📝", id: "editMessage" });
    },
    onSuccess: () => {
      toast("Message edited", { icon: "📝", id: "editMessage" });
    },
    onError: () => {
      toast.error("Error editing message", { id: "editMessage" });
    },
  });

  const handleEditSubmit = useCallback(
    (e: FormEvent<HTMLFormElement>) => {
      e.preventDefault();
      const form = e.currentTarget;
      const formData = new FormData(form);
      if (!formData.get("message-edit") || !formData.get("message-id")) {
        return;
      }
      editMutation({
        chatId,
        messageId: formData.get("message-id") as MessagesMessageid,
        message: formData.get("message-edit") as string,
      });
      setEditModalOpen(false);
    },
    [editMutation],
  );
  const [locked, setLocked] = useState(false);

  useEffect(() => {
    if (
      messagesContainerRef.current &&
      !locked &&
      !query.isLoading &&
      !query.isFetching
    ) {
      messagesContainerRef.current.scrollTop =
        messagesContainerRef.current.scrollHeight;
    }
    setLocked(false);
  }, [messages, typingStatus]);

  return (
    <div className="flex h-full w-full flex-col overflow-y-auto">
      <ChatMessageList ref={messagesContainerRef}>
        <AnimatePresence key="chat-messages">
          {query.hasNextPage && (
            <LoadingButton
              aria-label="Load More Messages"
              loading={query.isFetchingNextPage}
              variant="secondary"
              key="load-more"
              disabled={!query.hasNextPage || query.isFetchingNextPage}
              onClick={async () => {
                setLocked(true);
                await query.fetchNextPage();
              }}
              className="mb-3"
            >
              {query.isFetchingNextPage
                ? "Caricamento..."
                : "Carica messaggi precedenti"}
            </LoadingButton>
          )}

          {messages.map((message, index) => {
            const variant = getMessageVariant(message.sender, userData.id);

            const isNextSameSender =
              index + 1 < messages.length &&
              messages[index + 1]?.sender == message.sender;

            const isPreviousSameSender =
              index - 1 >= 0 && messages[index - 1]?.sender == message.sender;

            const isPrevSameDay =
              index - 1 >= 0 &&
              new Date(messages[index - 1]!.time).toDateString() ===
                new Date(message.time).toDateString();

            return (
              <motion.div
                key={message.messageid}
                layout
                initial={{ opacity: 0, scale: 1, y: 50, x: 0 }}
                animate={{ opacity: 1, scale: 1, y: 0, x: 0 }}
                exit={{ opacity: 0, scale: 1, y: 1, x: 0 }}
                transition={{
                  opacity: { duration: 0.1 },
                  layout: {
                    type: "spring",
                    bounce: 0.3,
                    duration: 0.3,
                  },
                }}
                style={{ originX: 0.5, originY: 0.5 }}
                className={cn(
                  "flex flex-col gap-2 pb-4",
                  isNextSameSender && "pb-0.5",
                )}
              >
                {!isPrevSameDay && (
                  <span className="mx-auto rounded-md bg-muted px-2 py-1 text-center text-xs text-muted-foreground">
                    {new Date(message.time).toLocaleDateString("it", {
                      day: "2-digit",
                      month: "2-digit",
                      year: "2-digit",
                    })}
                  </span>
                )}
                <ChatBubble variant={variant}>
                  {isNextSameSender ? (
                    <div className="size-6"></div>
                  ) : (
                    <UserAvatar userId={message.sender} className="size-6" />
                  )}

                  <div className="flex flex-col gap-1">
                    {!isPreviousSameSender && (
                      <p
                        className={cn(
                          "text-sm font-semibold",
                          variant === "sent" && "text-right",
                        )}
                        style={{
                          color: getUserColor(message.sender),
                        }}
                      >
                        {message.sender_nome}
                      </p>
                    )}
                    <ChatBubbleMessage
                      isLoading={false}
                      className={cn(isNextSameSender && "rounded-lg")}
                    >
                      {message.message}
                      <div className="flex items-center gap-2">
                        {userData.id == message.sender && (
                          <ChatBubbleReadStatus isread={message.isread} />
                        )}
                        {message.time && (
                          <ChatBubbleTimestamp
                            timestamp={new Date(message.time).toLocaleString(
                              "it",
                              {
                                day: "2-digit",
                                month: "short",
                                hour: "2-digit",
                                minute: "2-digit",
                              },
                            )}
                          />
                        )}
                      </div>
                    </ChatBubbleMessage>
                  </div>
                  <ChatBubbleActionWrapper show={userData.isAdmin}>
                    <ChatBubbleAction
                      className="size-7 hover:bg-red-50 hover:text-red-500"
                      key={"delete"}
                      icon={<Trash2 className="size-4" />}
                      onClick={() => {
                        setMsgSelected(message);
                        handleDeleteOpen(true);
                      }}
                    />
                    <ChatBubbleAction
                      className="size-7 hover:bg-blue-50 hover:text-blue-500"
                      key={"edit"}
                      icon={<Pencil className="size-4" />}
                      onClick={() => {
                        setMsgSelected(message);
                        handleEditOpen(true);
                      }}
                    />
                  </ChatBubbleActionWrapper>
                </ChatBubble>
              </motion.div>
            );
          })}

          <Typers
            currentTypers={typingStatus}
            messageLenght={messages.length}
            userId={userData.id}
          />
        </AnimatePresence>
      </ChatMessageList>
      <EditMessageDialog
        open={editModalOpen}
        onOpenChange={handleEditOpen}
        msgEdit={msgSelected}
        handleEditSubmit={handleEditSubmit}
      />
      <DeleteMessageDialog
        open={deleteModalOpen}
        onOpenChange={handleDeleteOpen}
        msgDelete={msgSelected}
        handleDeleteSubmit={(messageId) => {
          deleteMutation({ chatId, messageId });
        }}
      />
    </div>
  );
};

const Typers = ({
  currentTypers,
  messageLenght,
  userId,
}: {
  currentTypers: WhoIsTyping[];
  messageLenght: number;
  userId: UsersId;
}) => {
  return (
    <>
      {currentTypers.map((typer, index) => {
        if (typer.userId === userId) return null;
        const variant = "received";

        return (
          <motion.div
            key={"typers" + messageLenght + index}
            layout
            initial={{ opacity: 0, scale: 1, y: 50, x: 0 }}
            animate={{ opacity: 1, scale: 1, y: 0, x: 0 }}
            exit={{ opacity: 0, scale: 1, y: 1, x: 0 }}
            transition={{
              opacity: { duration: 0.1 },
              layout: {
                type: "spring",
                bounce: 0.3,
                duration: 0.3,
              },
            }}
            style={{ originX: 0.5, originY: 0.5 }}
            className="flex flex-col gap-2 py-2"
          >
            <ChatBubble variant={variant}>
              <UserAvatar userId={typer.userId} className="size-6" />

              <ChatBubbleMessage isLoading={true}></ChatBubbleMessage>
            </ChatBubble>
          </motion.div>
        );
      })}
    </>
  );
};

const EditMessageDialog = ({
  open,
  onOpenChange,
  msgEdit,
  handleEditSubmit,
}: {
  open: boolean;
  onOpenChange: (status: boolean) => void;
  msgEdit: ChatMessage | null;
  handleEditSubmit: (e: FormEvent<HTMLFormElement>) => void;
}) => {
  const { t } = useTranslation();
  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>{t.modifica}</DialogTitle>
          <DialogDescription className="sr-only">Edit</DialogDescription>
        </DialogHeader>
        {msgEdit && (
          <form onSubmit={handleEditSubmit} method="post">
            <div className="flex items-center gap-3">
              <label htmlFor="id" className="sr-only">
                ID
              </label>
              <Input
                id="id"
                type="text"
                className="hidden"
                name="message-id"
                value={msgEdit.messageid}
                readOnly
              />
              <label htmlFor="message-edit" className="sr-only">
                Modifica messaggio
              </label>
              <Input
                id="message-edit"
                type="text"
                placeholder="Modifica messaggio"
                className="mt-0"
                name="message-edit"
                defaultValue={msgEdit.message || undefined}
              />
              <Button type="submit">{t.salva}</Button>
            </div>
          </form>
        )}
      </DialogContent>
    </Dialog>
  );
};

const DeleteMessageDialog = ({
  open,
  onOpenChange,
  msgDelete,
  handleDeleteSubmit,
}: {
  open: boolean;
  onOpenChange: (status: boolean) => void;
  msgDelete: ChatMessage | null;
  handleDeleteSubmit: (msgId: MessagesMessageid) => void;
}) => {
  const { t } = useTranslation();
  return (
    <>
      {msgDelete && (
        <AlertDialog open={open} onOpenChange={onOpenChange}>
          <AlertDialogContent>
            <AlertDialogHeader>
              <AlertDialogTitle>Vuoi eliminare il messaggio?</AlertDialogTitle>
              <AlertDialogDescription>
                Questa azione non può essere annullata.
              </AlertDialogDescription>
            </AlertDialogHeader>
            <AlertDialogFooter>
              <AlertDialogCancel>{t.annulla}</AlertDialogCancel>
              <AlertDialogAction
                aria-label="Delete Message"
                onClick={() => handleDeleteSubmit(msgDelete.messageid)}
              >
                {t.procedi}
              </AlertDialogAction>
            </AlertDialogFooter>
          </AlertDialogContent>
        </AlertDialog>
      )}
    </>
  );
};

const getMessageVariant = (messageName: string, selectedUserName: string) =>
  messageName !== selectedUserName ? "received" : "sent";
