"use client";

import { useEffect, useState } from "react";
import { createPortal } from "react-dom";
import Link from "next/link";
import { X, UserPlus, Check, MessageCircle, Loader2 } from "lucide-react";
import { Avatar } from "./Avatar";
import { sfx } from "@/lib/sfx";
import { useConnectionWords } from "@/lib/site-context";
import type { User } from "@/lib/types";
import clsx from "clsx";

type Person = User & { isFollowing: boolean; isSelf: boolean };
type Kind = "followers" | "following" | "friends";

/**
 * What each list is called.
 *
 * On a friends site there is only one list worth showing -- two people
 * either are friends or they are not -- so "followers" and "following"
 * would be two names for halves of the same thing. The tab strip drops to
 * a single tab there rather than offering distinctions the site does not
 * make.
 */
const TITLES: Record<Kind, string> = {
  followers: "Followers",
  following: "Following",
  friends: "Mutuals",
};

/** Followers, following or friends, with follow and message actions. */
export function ConnectionsModal({
  username,
  kind,
  onClose,
}: {
  username: string;
  kind: Kind;
  onClose: () => void;
}) {
  const c = useConnectionWords();
  const friendly = c.mode === "friend";
  // On a friends site every list is the friends list, whichever count was
  // clicked to get here.
  const [tab, setTab] = useState<Kind>(friendly ? "friends" : kind);
  const [people, setPeople] = useState<Person[] | null>(null);
  const [query, setQuery] = useState("");

  const titleFor = (k: Kind) => (friendly ? c.plural : TITLES[k]);
  const tabs: Kind[] = friendly ? ["friends"] : ["followers", "following", "friends"];

  useEffect(() => {
    setPeople(null);
    fetch(`/api/users/${username}/connections?kind=${tab}`)
      .then((r) => (r.ok ? r.json() : []))
      .then((d) => setPeople(Array.isArray(d) ? d : []))
      .catch(() => setPeople([]));
  }, [username, tab]);

  async function toggleFollow(p: Person) {
    setPeople(
      (list) =>
        list?.map((x) =>
          x.id === p.id ? { ...x, isFollowing: !x.isFollowing } : x
        ) ?? null
    );
    sfx.click();
    await fetch(`/api/users/${p.username}/follow`, { method: "POST" }).catch(() => {});
  }

  const shown =
    people?.filter((p) => {
      const q = query.trim().toLowerCase();
      if (!q) return true;
      return (
        p.name.toLowerCase().includes(q) || p.username.toLowerCase().includes(q)
      );
    }) ?? null;

  return createPortal(
    <div className="nm-back" onClick={onClose}>
      <div className="cn-card" onClick={(e) => e.stopPropagation()}>
        <div className="cn-head">
          <span className="cn-title">{titleFor(tab)}</span>
          <button onClick={onClose} className="nm-x">
            <X size={18} />
          </button>
        </div>

        {tabs.length > 1 && (
          <div className="cn-tabs">
            {tabs.map((k) => (
              <button
                key={k}
                onClick={() => setTab(k)}
                className={clsx("cn-tab", tab === k && "on")}
              >
                {TITLES[k]}
              </button>
            ))}
          </div>
        )}

        <input
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          placeholder="Search people..."
          className="cn-search"
        />

        <div className="cn-list">
          {shown === null && (
            <p className="cn-empty">
              <Loader2 size={18} className="animate-spin" />
            </p>
          )}

          {shown?.map((p) => (
            <div key={p.id} className="cn-row">
              <Link href={`/${p.username}`} onClick={onClose} className="cn-person">
                <Avatar user={p} size={36} />
                <span className="min-w-0">
                  <b>{p.name}</b>
                  <em>@{p.username}</em>
                  {p.bio && <i>{p.bio}</i>}
                </span>
              </Link>

              {!p.isSelf && (
                <span className="cn-actions">
                  <button
                    onClick={() => toggleFollow(p)}
                    className={clsx("cn-follow", p.isFollowing && "on")}
                  >
                    {p.isFollowing ? <Check size={13} /> : <UserPlus size={13} />}
                    {p.isFollowing ? c.connected : c.connect}
                  </button>
                  <Link
                    href={`/messages?to=${p.username}`}
                    onClick={onClose}
                    className="cn-msg"
                    title="Message"
                  >
                    <MessageCircle size={15} />
                  </Link>
                </span>
              )}
            </div>
          ))}

          {shown?.length === 0 && (
            <p className="cn-empty">
              {query ? "Nobody matches that." : `No ${TITLES[tab].toLowerCase()} yet.`}
            </p>
          )}
        </div>
      </div>
    </div>,
    document.body
  );
}
