"use client";

import { useEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";
import Link from "next/link";
import { Check, UserPlus } from "lucide-react";
import { Avatar } from "./Avatar";
import { useAuth } from "@/lib/auth-context";
import { formatCount } from "@/lib/utils";
import { sfx } from "@/lib/sfx";
import { firework } from "@/lib/particles";
import type { User } from "@/lib/types";
import clsx from "clsx";

type Profile = User & {
  followerCount?: number;
  followingCount?: number;
  isFollowing?: boolean;
  coverGradient?: string;
};

/** Small cache so hovering the same person repeatedly doesn't refetch. */
const cache = new Map<string, Profile>();

/**
 * Wraps a name or avatar so hovering it reveals a profile preview, the way
 * most social apps do. Opens after a short delay to avoid firing on every
 * passing mouse movement.
 */
export function ProfileHoverCard({
  username,
  user,
  children,
  className,
}: {
  username: string;
  /** Known author details, so the card renders instantly. */
  user?: User;
  children: React.ReactNode;
  className?: string;
}) {
  const { user: me } = useAuth();
  const [open, setOpen] = useState(false);
  const [pos, setPos] = useState<{ x: number; y: number; above: boolean } | null>(null);
  const [profile, setProfile] = useState<Profile | null>(cache.get(username) ?? user ?? null);
  const [following, setFollowing] = useState(false);
  const wrapRef = useRef<HTMLSpanElement>(null);
  const openTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
  const closeTimer = useRef<ReturnType<typeof setTimeout> | null>(null);

  useEffect(() => {
    return () => {
      if (openTimer.current) clearTimeout(openTimer.current);
      if (closeTimer.current) clearTimeout(closeTimer.current);
    };
  }, []);

  function scheduleOpen() {
    if (closeTimer.current) clearTimeout(closeTimer.current);
    if (openTimer.current) clearTimeout(openTimer.current);
    openTimer.current = setTimeout(async () => {
      const el = wrapRef.current;
      if (!el) return;
      // The wrapper is layout-transparent, so measure what it contains.
      const target = (el.firstElementChild as HTMLElement) ?? el;
      const r = target.getBoundingClientRect();
      // Flip above the trigger when there isn't room below.
      const above = r.bottom + 300 > window.innerHeight;
      setPos({
        x: Math.min(Math.max(12, r.left), window.innerWidth - 312),
        y: above ? r.top - 8 : r.bottom + 2,
        above,
      });
      setOpen(true);

      if (!cache.has(username)) {
        const res = await fetch(`/api/users/${username}`).catch(() => null);
        if (res && res.ok) {
          const d = await res.json();
          const p: Profile = d.user ?? d;
          cache.set(username, p);
          setProfile(p);
          setFollowing(Boolean(p.isFollowing));
        }
      } else {
        const p = cache.get(username)!;
        setProfile(p);
        setFollowing(Boolean(p.isFollowing));
      }
    }, 420);
  }

  function scheduleClose() {
    if (openTimer.current) clearTimeout(openTimer.current);
    closeTimer.current = setTimeout(() => setOpen(false), 220);
  }

  async function toggleFollow(e: React.MouseEvent<HTMLButtonElement>) {
    if (!following) {
      firework(e.currentTarget, ["#7b2ff7", "#d43cae", "#ffffff"]);
      sfx.friend();
    }
    setFollowing((v) => !v);
    await fetch(`/api/users/${username}/follow`, { method: "POST" }).catch(() => {});
  }

  const isMe = me?.username === username;

  return (
    <>
      <span
        ref={wrapRef}
        className={className}
        style={{ display: "contents" }}
        onMouseEnter={scheduleOpen}
        onMouseLeave={scheduleClose}
      >
        {children}
      </span>

      {open &&
        pos &&
        createPortal(
          <div
            className="hov-card"
            style={{
              left: pos.x,
              top: pos.y,
              transform: pos.above ? "translateY(-100%)" : undefined,
            }}
            onMouseEnter={() => {
              if (closeTimer.current) clearTimeout(closeTimer.current);
            }}
            onMouseLeave={scheduleClose}
          >
            <span
              className={clsx(
                "hov-cover bg-gradient-to-br",
                profile?.avatarColor ?? "from-fuchsia-500 to-purple-600"
              )}
            />

            <div className="hov-body">
              <div className="flex items-start justify-between gap-2 -mt-8">
                {profile ? (
                  <Link href={`/${username}`}>
                    <Avatar user={profile} size={56} />
                  </Link>
                ) : (
                  <span className="w-14 h-14 rounded-full bg-neutral-200 dark:bg-neutral-800 animate-pulse" />
                )}

                {!isMe && (
                  <button
                    onClick={toggleFollow}
                    className={clsx("hov-follow", following && "done")}
                  >
                    {following ? (
                      <>
                        <Check size={12} /> Following
                      </>
                    ) : (
                      <>
                        <UserPlus size={12} /> Follow
                      </>
                    )}
                  </button>
                )}
              </div>

              <Link href={`/${username}`} className="hov-name">
                {profile?.name ?? username}
              </Link>

              {profile?.bio && <p className="hov-bio">{profile.bio}</p>}

              <div className="hov-stats">
                <span>
                  <b>{formatCount(profile?.followingCount ?? 0)}</b> Following
                </span>
                <span>
                  <b>{formatCount(profile?.followerCount ?? 0)}</b> Followers
                </span>
              </div>
            </div>
          </div>,
          document.body
        )}
    </>
  );
}
