import { useCallback, useEffect, useRef, useState } from "react";
import { Link, useParams } from "react-router";

import { API_URL } from "../config/api.ts";
import type { Dump } from "../model.ts";
import { deserializeDump } from "../model.ts";
import { useAuth } from "../hooks/useAuth.ts";
import { useWS } from "../hooks/useWS.ts";
import { useDumpListSync } from "../hooks/useDumpListSync.ts";
import { useFading } from "../hooks/useFading.ts";
import { useUserDumpFeed } from "../hooks/useUserDumpFeed.ts";
import { DumpCard } from "../components/DumpCard.tsx";
import { ProfileSubpageHeader } from "../components/ProfileSubpageHeader.tsx";
import { PageShell } from "../components/PageShell.tsx";
import { PageError } from "../components/PageError.tsx";

export function UserUpvoted() {
  const { username } = useParams();
  const { user: me } = useAuth();
  const { voteCounts, myVotes, lastVoteEvent, castVote, removeVote } = useWS();

  const [votedIds, setVotedIds] = useState<Set<string>>(new Set());
  const { fading, startFading, cancelFading, cancelAll } = useFading();
  const prevMyVotesRef = useRef<Set<string> | null>(null);

  const onItemsAppended = useCallback((newItems: Dump[]) => {
    setVotedIds((prev) => new Set([...prev, ...newItems.map((d) => d.id)]));
  }, []);

  const { state, setState, setItems, sentinelRef } = useUserDumpFeed(
    username,
    "votes",
    `feed:user-upvoted-full:${username ?? ""}`,
    { onItemsAppended },
  );

  useDumpListSync(setItems);

  const profileUserId = state.status === "loaded" ? state.profileUser.id : null;

  // Reset vote tracking when username changes
  useEffect(() => {
    cancelAll();
    setVotedIds(new Set());
    prevMyVotesRef.current = null;
  }, [username]);

  // Seed votedIds once items are loaded
  useEffect(() => {
    if (state.status !== "loaded") return;
    setVotedIds(new Set(state.items.map((d) => d.id)));
  }, [state.status]);

  // Own profile: keep votedIds in sync with myVotes
  useEffect(() => {
    if (!profileUserId || me?.id !== profileUserId) return;
    if (prevMyVotesRef.current === null) {
      setVotedIds(new Set(myVotes));
      prevMyVotesRef.current = new Set(myVotes);
      return;
    }
    const prev = prevMyVotesRef.current;
    setVotedIds(new Set(myVotes));
    for (const id of prev) if (!myVotes.has(id)) startFading(id);
    for (const id of myVotes) if (!prev.has(id)) cancelFading(id);
    prevMyVotesRef.current = new Set(myVotes);
  }, [myVotes, me, profileUserId, startFading, cancelFading]);

  // WS vote events
  useEffect(() => {
    if (!lastVoteEvent || !profileUserId) return;
    const { dumpId, voterId, action } = lastVoteEvent;
    if (voterId !== profileUserId) return;

    if (action === "remove") {
      setVotedIds((prev) => {
        const n = new Set(prev);
        n.delete(dumpId);
        return n;
      });
      startFading(dumpId);
    } else {
      setVotedIds((prev) => new Set([...prev, dumpId]));
      cancelFading(dumpId);
      fetch(`${API_URL}/api/dumps/${dumpId}`)
        .then((r) => r.json())
        .then((body) => {
          if (!body.success) return;
          const dump = deserializeDump(body.data);
          setState((s) => {
            if (s.status !== "loaded" || s.items.some((d) => d.id === dumpId)) {
              return s;
            }
            return { ...s, items: [dump, ...s.items] };
          });
        })
        .catch(() => {});
    }
  }, [lastVoteEvent, profileUserId, startFading, cancelFading]);

  if (state.status === "loading") {
    return (
      <PageShell>
        <p className="page-loading">Loading…</p>
      </PageShell>
    );
  }

  if (state.status === "error") {
    return (
      <PageError
        message={state.error}
        actions={
          <Link to={`/users/${username}`} className="btn-border">
            ← Back to profile
          </Link>
        }
      />
    );
  }

  const { profileUser, items: votes, hasMore, loadingMore } = state;
  const visibleDumps = votes.filter((d) =>
    votedIds.has(d.id) || d.id in fading
  );

  return (
    <PageShell>
      <ProfileSubpageHeader
        username={username!}
        profileUser={profileUser}
        title="Upvoted"
      />

      {visibleDumps.length === 0
        ? <p className="empty-state">Nothing here yet.</p>
        : (
          <ul className="dump-feed">
            {visibleDumps.map((dump) => {
              const phase = fading[dump.id];
              const extraCls = phase === "cooldown"
                ? "dump-card--fading"
                : phase === "dismissing"
                ? "dump-card--dismissing"
                : undefined;
              return (
                <DumpCard
                  key={dump.id}
                  dump={dump}
                  voteCount={voteCounts[dump.id] ?? dump.voteCount}
                  voted={myVotes.has(dump.id)}
                  canVote={!!me}
                  castVote={castVote}
                  removeVote={removeVote}
                  className={extraCls}
                  isOwner={!!me && me.id === dump.userId}
                />
              );
            })}
          </ul>
        )}

      <div ref={sentinelRef} />
      {loadingMore && <p className="feed-loading-more">Loading more…</p>}
      {!hasMore && visibleDumps.length > 0 && (
        <p className="index-status">All {votes.length} upvoted dumps loaded.</p>
      )}
    </PageShell>
  );
}
