import { useEffect, useMemo, useRef, useState } from "react";
import ForceGraph3D from "react-force-graph-3d";

import { type TopUser, type InteractionGraph } from "../types/ApiTypes";

import StatsStyling from "../styles/stats_styling";
import Card from "./Card";
import {
  buildReplyPairSpec,
  toText,
  buildUserSpec,
  type CorpusExplorerSpec,
} from "../utils/corpusExplorer";

const styles = StatsStyling;

type GraphLink = {
  source: string;
  target: string;
  value: number;
};

function toGraphData(apiData: InteractionGraph) {
  const links: GraphLink[] = [];
  const connectedNodeIds = new Set<string>();

  for (const [source, targets] of Object.entries(apiData)) {
    for (const [target, count] of Object.entries(targets)) {
      if (count < 2 || source === "[deleted]" || target === "[deleted]") {
        continue;
      }
      links.push({ source, target, value: count });
      connectedNodeIds.add(source);
      connectedNodeIds.add(target);
    }
  }

  const filteredNodes = Array.from(connectedNodeIds, (id) => ({ id }));

  return { nodes: filteredNodes, links };
}

type UserStatsProps = {
  topUsers: TopUser[];
  interactionGraph: InteractionGraph;
  totalUsers: number;
  mostCommentHeavyUser: { author: string; commentShare: number } | null;
  onExplore: (spec: CorpusExplorerSpec) => void;
};

const UserStats = ({
  topUsers,
  interactionGraph,
  totalUsers,
  mostCommentHeavyUser,
  onExplore,
}: UserStatsProps) => {
  const graphData = useMemo(
    () => toGraphData(interactionGraph),
    [interactionGraph],
  );
  const graphContainerRef = useRef<HTMLDivElement | null>(null);
  const [graphSize, setGraphSize] = useState({ width: 720, height: 540 });

  useEffect(() => {
    const updateGraphSize = () => {
      const containerWidth = graphContainerRef.current?.clientWidth ?? 720;
      const nextWidth = Math.max(320, Math.floor(containerWidth));
      const nextHeight = nextWidth < 700 ? 300 : 540;
      setGraphSize({ width: nextWidth, height: nextHeight });
    };

    updateGraphSize();
    window.addEventListener("resize", updateGraphSize);

    return () => window.removeEventListener("resize", updateGraphSize);
  }, []);

  const connectedUsers = graphData.nodes.length;
  const totalInteractions = graphData.links.reduce(
    (sum, link) => sum + link.value,
    0,
  );
  const avgInteractionsPerConnectedUser = connectedUsers
    ? totalInteractions / connectedUsers
    : 0;

  const strongestLink = graphData.links.reduce<GraphLink | null>(
    (best, current) => {
      if (!best || current.value > best.value) {
        return current;
      }
      return best;
    },
    null,
  );

  const mostActiveUser = topUsers.find((u) => u.author !== "[deleted]");
  const strongestLinkSource = strongestLink ? toText(strongestLink.source) : "";
  const strongestLinkTarget = strongestLink ? toText(strongestLink.target) : "";

  return (
    <div style={styles.page}>
      <div style={{ ...styles.container, ...styles.grid }}>
        <Card
          label="Users"
          value={totalUsers.toLocaleString()}
          sublabel={`${connectedUsers.toLocaleString()} users in filtered graph`}
          style={{ gridColumn: "span 3" }}
        />
        <Card
          label="Replies"
          value={totalInteractions.toLocaleString()}
          sublabel="Links with at least 2 replies"
          style={{ gridColumn: "span 3" }}
        />
        <Card
          label="Replies per Connected User"
          value={avgInteractionsPerConnectedUser.toFixed(1)}
          sublabel="Average from visible graph links"
          style={{ gridColumn: "span 3" }}
        />
        <Card
          label="Most Active User"
          value={mostActiveUser?.author ?? "-"}
          sublabel={
            mostActiveUser
              ? `${mostActiveUser.count.toLocaleString()} events`
              : "No user activity found"
          }
          rightSlot={
            mostActiveUser ? (
              <button
                onClick={() => onExplore(buildUserSpec(mostActiveUser.author))}
                style={styles.buttonSecondary}
              >
                Explore
              </button>
            ) : null
          }
          style={{ gridColumn: "span 3" }}
        />

        <Card
          label="Strongest User Link"
          value={
            strongestLinkSource && strongestLinkTarget
              ? `${strongestLinkSource} -> ${strongestLinkTarget}`
              : "-"
          }
          sublabel={
            strongestLink
              ? `${strongestLink.value.toLocaleString()} replies`
              : "No graph links after filtering"
          }
          rightSlot={
            strongestLinkSource && strongestLinkTarget ? (
              <button
                onClick={() =>
                  onExplore(buildReplyPairSpec(strongestLinkSource, strongestLinkTarget))
                }
                style={styles.buttonSecondary}
              >
                Explore
              </button>
            ) : null
          }
          style={{ gridColumn: "span 6" }}
        />
        <Card
          label="Most Comment-Heavy User"
          value={mostCommentHeavyUser?.author ?? "-"}
          sublabel={
            mostCommentHeavyUser
              ? `${Math.round(mostCommentHeavyUser.commentShare * 100)}% comments`
              : "No user distribution available"
          }
          rightSlot={
            mostCommentHeavyUser ? (
              <button
                onClick={() => onExplore(buildUserSpec(mostCommentHeavyUser.author))}
                style={styles.buttonSecondary}
              >
                Explore
              </button>
            ) : null
          }
          style={{ gridColumn: "span 6" }}
        />

        <div style={{ ...styles.card, gridColumn: "span 12" }}>
          <h2 style={styles.sectionTitle}>User Interaction Graph</h2>
          <p style={styles.sectionSubtitle}>
            Each node is a user, and each link shows replies between them.
          </p>
          <div
            ref={graphContainerRef}
            style={{ width: "100%", height: graphSize.height }}
          >
            <ForceGraph3D
              width={graphSize.width}
              height={graphSize.height}
              graphData={graphData}
              nodeAutoColorBy="id"
              linkDirectionalParticles={1}
              linkDirectionalParticleSpeed={0.004}
              linkWidth={(link) => Math.sqrt(Number(link.value))}
              nodeLabel={(node) => `${node.id}`}
              onNodeClick={(node) => {
                const userId = toText(node.id);
                if (userId) {
                  onExplore(buildUserSpec(userId));
                }
              }}
              onLinkClick={(link) => {
                const source = toText(link.source);
                const target = toText(link.target);
                if (source && target) {
                  onExplore(buildReplyPairSpec(source, target));
                }
              }}
            />
          </div>
        </div>
      </div>
    </div>
  );
};

export default UserStats;
