import React from "https://esm.sh/react@19?dev";
import ReactDOM from "https://esm.sh/react-dom@19/client?dev";

function ChatRoom() {
  const [message, setMessage] = React.useState("");
  const [isUserConnected, setIsUserConnected] = React.useState(false);
  const [userData, setUserData] = React.useState({
    userID: "",
    name: "",
  });
  const [socketMessages, setSocketMessages] = React.useState({});
  const [loggedInUsers, setLoggedInUsers] = React.useState([]);
  const [selectedUser, setSelectedUser] = React.useState(null);
  const [unreadMessages, setUnreadMessages] = React.useState({});
  const socketRef = React.useRef(null);
  const handleClick = (e) => {
    e.preventDefault();
    if (!selectedUser) {
      alert("Select a user to send a message");
      return;
    }
    if (message && socketRef.current) {
      socketRef.current.emit(
        "chat-message",
        JSON.stringify({
          content: {
            recipientUserID: selectedUser.userID,
            message,
          },
          senderName: userData.name,
          senderID: userData.userID,
        }),
      );
      setSocketMessages((prev) => {
        if (!(selectedUser.userID in prev)) {
          return {
            ...prev,
            [selectedUser.userID]: [
              {
                senderName: userData.name,
                senderID: userData.userID,
                message,
              },
            ],
          };
        } else {
          return {
            ...prev,
            [selectedUser.userID]: [
              ...prev[selectedUser.userID],
              {
                senderName: userData.name,
                senderID: userData.userID,
                message,
              },
            ],
          };
        }
      });
      setMessage("");
    }
  };
  React.useEffect(() => {
    const handlePrivateMessage = (msg) => {
      const { senderID, senderName, message } = JSON.parse(msg);
      setSocketMessages((prev) => {
        if (!(senderID in prev)) {
          return {
            ...prev,
            [senderID]: [{ senderName, senderID, message }],
          };
        }
        return {
          ...prev,
          [senderID]: [...prev[senderID], { senderName, senderID, message }],
        };
      });
      if (selectedUser === null || selectedUser.userID !== senderID) {
        setUnreadMessages((prev) => {
          if (!(senderID in prev)) {
            return {
              ...prev,
              [senderID]: 1,
            };
          }
          return {
            ...prev,
            [senderID]: prev[senderID] + 1,
          };
        });
      }
    };
    if (!isUserConnected) return;
    socketRef.current.on("private-message", handlePrivateMessage);
    return () => {
      if (socketRef.current) {
        socketRef.current.off("private-message", handlePrivateMessage);
      }
    };
  }, [isUserConnected, selectedUser]);
  const connectToSocket = (e) => {
    e.preventDefault();
    if (!userData.userID || !userData.name) return;

    const socket = io({ auth: userData });
    socketRef.current = socket;

    socketRef.current.on("user-login", (user) => {
      const { userID, userName } = JSON.parse(user);
      setLoggedInUsers((prev) => [...prev, { userID, userName }]);
    });
    socketRef.current.on("user-logout", (user) => {
      const { userID, userName } = JSON.parse(user);
      setLoggedInUsers((prev) =>
        prev.filter((loggedIn) => loggedIn.userID !== userID),
      );
    });
    socketRef.current.on("already-logged-in-users", (users) => {
      const { alreadyLoggedInUsers } = JSON.parse(users);
      setLoggedInUsers(alreadyLoggedInUsers);
    });
    setIsUserConnected(true);
  };
  const disconnectSocket = () => {
    socketRef.current.emit(
      "user-logout",
      JSON.stringify({
        userID: userData.userID,
        userName: userData.name,
      }),
    );
    socketRef.current.disconnect();
    socketRef.current = null;
    setUserData({
      userID: "",
      name: "",
    });
    setIsUserConnected(false);
    setSocketMessages({});
    // Store unread count in DB?
    setUnreadMessages({});
    setSelectedUser(null);
  };
  const interfaceFunctions = {
    renderHeaderContent: () => {
      if (isUserConnected) {
        return (
          <div id="connection-bar">
            <p>
              Connected ✈️ - {userData.name} #{userData.userID}
            </p>
            <button onClick={disconnectSocket}>Disconnect</button>
          </div>
        );
      }
      return (
        <form id="connection-form">
          <input
            id="user-id"
            placeholder="User ID"
            value={userData.userID}
            onChange={(e) =>
              setUserData({
                ...userData,
                userID: e.target.value,
              })
            }
          />

          <input
            id="user-name"
            placeholder="Name"
            value={userData.name}
            onChange={(e) =>
              setUserData({
                ...userData,
                name: e.target.value,
              })
            }
          />
          <button onClick={connectToSocket}>Connect</button>
        </form>
      );
    },
    loggedInList: () => {
      if (!isUserConnected) {
        return <p>Log in to see who's connected</p>;
      }
      if (loggedInUsers.length === 0) {
        return <p>You're the only one online right now</p>;
      }
      return loggedInUsers.map(({ userID, userName }) => (
        <li
          className={`online-user ${selectedUser?.userID === userID ? "active-convo" : ""}`}
          key={userID}
          onClick={() => {
            setSelectedUser((prev) =>
              prev?.userID === userID ? null : { userID, userName },
            );
            setUnreadMessages((prev) => {
              return {
                ...prev,
                [userID]: 0,
              };
            });
          }}
        >
          <span>🟢 {userName}</span>
          {unreadMessages[userID] ? (
            <span className="badge">{unreadMessages[userID]}</span>
          ) : null}
        </li>
      ));
    },
    messagesList: () => {
      if (!isUserConnected) return null;
      if (loggedInUsers.length === 0) return null;
      if (selectedUser) {
        if (
          socketMessages[selectedUser.userID] &&
          socketMessages[selectedUser.userID].length > 0
        ) {
          return (
            <ul id="messages-list">
              {socketMessages[selectedUser.userID]?.map(
                ({ senderName, senderID, message }, idx) => {
                  return (
                    <li
                      className={`${senderID === userData.userID ? "to" : "from"}-message`}
                      key={message.concat(idx)}
                    >
                      {message}
                    </li>
                  );
                },
              )}
            </ul>
          );
        } else {
          return (
            <div className="no-messages">
              <strong>
                <i>
                  Send {selectedUser.userName} a message to start the
                  conversation!
                </i>
              </strong>
            </div>
          );
        }
      } else {
        return (
          <div className="no-messages">
            <strong>
              <i>Select a conversation to view the messages</i>
            </strong>
          </div>
        );
      }
    },
    isMessageButtonDisabled: () => {
      if (!selectedUser) return true;
      return false;
    },
  };
  return (
    <>
      <header>{interfaceFunctions.renderHeaderContent()}</header>
      <main>
        <div id="main-content">
          <ul id="logged-in">{interfaceFunctions.loggedInList()}</ul>
          <div id="messages">{interfaceFunctions.messagesList()}</div>
        </div>
      </main>
      <footer>
        <form id="chat-form">
          <input
            id="input"
            value={message}
            onChange={(e) => setMessage(e.target.value)}
            autoComplete="off"
          />
          <button
            onClick={handleClick}
            disabled={interfaceFunctions.isMessageButtonDisabled()}
          >
            Send
          </button>
        </form>
      </footer>
    </>
  );
}

const root = ReactDOM.createRoot(document.getElementById("app"));
root.render(<ChatRoom />);
