import Image from "next/image";
import { ReactNode, useEffect, useRef, useState } from "react";
import { Socket } from "socket.io-client";

type ChatPersonProps = {
  person: string;
  image: string;
};

function ChatPerson({ person, image }: ChatPersonProps) {
  return (
    <div className="flex p-2 items-center justify-center">
      <div className="rounded-full overflow-hidden m-2">
        <Image alt="bob" width={50} height={50} src={`/images/${image}`} />
      </div>
      <h1 className="text-3xl ml-3 text-center">{person}</h1>
    </div>
  );
}

type ChatMessageProps = {
  position: "left" | "right";
  text: string;
  color: string;
  deliveredTime?: Date;
};

function ChatMessage({ position, text, color, deliveredTime }: ChatMessageProps) {
  return (
    <div className={"chat " + (position == "left" ? "chat-start" : "chat-end")}>
      <div className={`chat-bubble chat-bubble-warning`}>{text}</div>
      {deliveredTime && (
        <div className="chat-footer opacity-50">{`${deliveredTime.getHours()}:${deliveredTime
          .getMinutes()
          .toString()
          .padStart(2, "0")}`}</div>
      )}
    </div>
  );
}

type ChatWindowProps = {
  socket: Socket;
  challenge: "challenge-1" | "challenge-2";
};

function ChatWindow({ socket, challenge }: ChatWindowProps) {
  const [text, setText] = useState("");
  const [messages, setMessages] = useState<ReactNode[]>([]);
  const scrollRef = useRef<any>(null);
  const [curBobMessage, setCurBobMessage] = useState<ReactNode>(null);
  const [bobCrashed, setBobCrashed] = useState(false);

  function createMessage(user: "bob" | "user", text: string, deliveredTime?: Date) {
    return (
      <ChatMessage
        color="warning"
        position={user == "bob" ? "left" : "right"}
        text={text}
        deliveredTime={deliveredTime || new Date()}
        key={text + new Date().toISOString()}
      />
    );
  }

  function bobMessageEnd(fullText: string) {
    setMessages((old) => [...old, createMessage("bob", fullText)]);
    setCurBobMessage(null);
  }

  useEffect(() => {
    socket.connect();
    socket.emit(challenge ?? "challenge-1");
  }, []);

  useEffect(() => {
    socket.removeAllListeners("outputFinished");
    socket.on("outputFinished", (args) => {
      bobMessageEnd(args);
    });

    socket.removeAllListeners("bobCrashed");
    socket.on("bobCrashed", (args) => {
      setBobCrashed(true);
    });
  }, [curBobMessage]);

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

    scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
  }, [messages, curBobMessage]);

  function sendMessage(text: string) {
    console.log("Sending message: ", text);
    setMessages((old) => [
      ...old,
      <ChatMessage
        color="warning"
        position="right"
        text={text}
        deliveredTime={new Date()}
        key={new Date().toISOString()}
      />,
    ]);

    socket.emit("input", text);
    setCurBobMessage(<ChatMessage color="warning" position="left" text="..." />);
  }

  return (
    <div className="flex flex-col h-[90vh] w-full rounded-3xl bg-[#29313d] p-4">
      <div ref={scrollRef} className="h-full overflow-y-auto">
        {messages.length == 0 ? <p className="text-center">Chat with Bob!</p> : messages}
        {curBobMessage}
        {bobCrashed && (
          <p className="text-center text-red-600">
            Bob Crashed :\
            <br />
            Please reload the page and try again.
          </p>
        )}
      </div>
      <input
        value={text}
        onChange={(e) => setText(e.currentTarget.value)}
        onKeyDown={(e) => {
          if (e.key == "Enter") {
            // commit
            if (text != "") {
              sendMessage(text);
              setText("");
            }
          }
        }}
        type="text"
        placeholder="Talk to Bob."
        disabled={curBobMessage != null || bobCrashed}
        className="input input-bordered input-warning w-full"
      />
    </div>
  );
}

type ChatProps = {
  socket: Socket;
  challenge: "challenge-1" | "challenge-2";
};

export default function Chat({ socket, challenge }: ChatProps) {
  return (
    <div className="w-screen h-screen">
      <div className="mx-auto w-1/2 h-screen">
        <ChatPerson person="Bob" image="robot.jpg" />
        <ChatWindow socket={socket} challenge={challenge} />
      </div>
    </div>
  );
}
