"use client";

import { useState, useMemo, useEffect, useCallback } from "react";
import { trpc } from "~/lib/trpc/client.js";
import {
  RESOURCE_VIEW_DOMAINS,
  PROJECT_VIEW_DOMAINS,
  type Domain,
  type GraphLink,
  type GraphNode,
} from "./domain-colors";
import { buildForceGraphData, getConnectedNodeIds, type PositionedNode, type ForceGraphData } from "./graph-data";

export type ViewMode = "resource" | "project";

export interface ComputationGraphResponse {
  nodes: GraphNode[];
  links: GraphLink[];
  meta?: Record<string, unknown>;
}

export interface ComputationGraphState {
  viewMode: ViewMode;
  setViewMode: (m: ViewMode) => void;
  resourceId: string;
  setResourceId: (id: string) => void;
  month: string;
  setMonth: (m: string) => void;
  projectId: string;
  setProjectId: (id: string) => void;
  resources: Array<{ id: string; displayName: string; eid: string }>;
  projects: Array<{ id: string; name: string; shortCode?: string | null }>;
  isLoading: boolean;
  activeDomains: Domain[];
  graphData: ForceGraphData;
  rawData: ComputationGraphResponse | null;
  highlightedNodes: Set<string> | null;
  setHighlightedNodes: (s: Set<string> | null) => void;
  hoveredNode: PositionedNode | null;
  setHoveredNode: (n: PositionedNode | null) => void;
  domainFilter: Set<Domain>;
  toggleDomain: (domain: Domain) => void;
  handleNodeClick: (nodeId: string) => void;
}

export function useComputationGraphData(): ComputationGraphState {
  const [viewMode, setViewMode] = useState<ViewMode>("resource");
  const [resourceId, setResourceId] = useState<string>("");
  const [month, setMonth] = useState(() => {
    const now = new Date();
    return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}`;
  });
  const [projectId, setProjectId] = useState<string>("");
  const [highlightedNodes, setHighlightedNodes] = useState<Set<string> | null>(null);
  const [hoveredNode, setHoveredNode] = useState<PositionedNode | null>(null);
  const [domainFilter, setDomainFilter] = useState<Set<Domain>>(new Set());

  // Load selectors
  const { data: resourceData } = trpc.resource.directory.useQuery(
    { isActive: true, limit: 500 },
    { staleTime: 60_000 },
  );
  const resources = resourceData?.resources ?? [];

  const { data: projectData } = trpc.project.list.useQuery(
    {},
    { staleTime: 60_000 },
  );
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  const projects: Array<{ id: string; name: string; shortCode?: string | null }> = (projectData as any)?.projects ?? (projectData as any) ?? [];

  // Auto-select first resource/project
  useEffect(() => {
    if (!resourceId && resources.length > 0) {
      setResourceId(resources[0]!.id);
    }
  }, [resources, resourceId]);

  useEffect(() => {
    if (!projectId && Array.isArray(projects) && projects.length > 0) {
      setProjectId(projects[0]!.id);
    }
  }, [projects, projectId]);

  // Fetch graph data
  const { data: resourceGraphData, isLoading: resourceLoading } = trpc.computationGraph.getResourceData.useQuery(
    { resourceId, month },
    { enabled: viewMode === "resource" && !!resourceId, staleTime: 30_000 },
  );

  const { data: projectGraphData, isLoading: projectLoading } = trpc.computationGraph.getProjectData.useQuery(
    { projectId },
    { enabled: viewMode === "project" && !!projectId, staleTime: 30_000 },
  );

  const rawData = viewMode === "resource" ? resourceGraphData : projectGraphData;
  const isLoading = viewMode === "resource" ? resourceLoading : projectLoading;
  const activeDomains = viewMode === "resource" ? RESOURCE_VIEW_DOMAINS : PROJECT_VIEW_DOMAINS;

  // Build graph data with positions
  const graphData = useMemo(() => {
    if (!rawData) return { nodes: [], links: [] };
    let filteredNodes = rawData.nodes as GraphNode[];
    if (domainFilter.size > 0) {
      filteredNodes = filteredNodes.filter((nd: GraphNode) => !domainFilter.has(nd.domain as Domain));
    }
    const filteredNodeIds = new Set(filteredNodes.map((nd: GraphNode) => nd.id));
    const filteredLinks = rawData.links.filter(
      (lk: { source: string; target: string }) =>
        filteredNodeIds.has(lk.source) && filteredNodeIds.has(lk.target),
    );
    return buildForceGraphData(filteredNodes, filteredLinks);
  }, [rawData, domainFilter]);

  // Domain filter toggle
  const toggleDomain = useCallback((domain: Domain) => {
    setDomainFilter((prev) => {
      const next = new Set(prev);
      if (next.has(domain)) {
        next.delete(domain);
      } else {
        next.add(domain);
      }
      return next;
    });
  }, []);

  // Node click → highlight path
  const handleNodeClick = useCallback(
    (nodeId: string) => {
      if (highlightedNodes?.has(nodeId)) {
        setHighlightedNodes(null);
      } else {
        const connected = getConnectedNodeIds(nodeId, graphData.links);
        setHighlightedNodes(connected);
      }
    },
    [graphData.links, highlightedNodes],
  );

  return {
    viewMode,
    setViewMode,
    resourceId,
    setResourceId,
    month,
    setMonth,
    projectId,
    setProjectId,
    resources,
    projects,
    isLoading,
    activeDomains,
    graphData,
    rawData: (rawData as ComputationGraphResponse | undefined) ?? null,
    highlightedNodes,
    setHighlightedNodes,
    hoveredNode,
    setHoveredNode,
    domainFilter,
    toggleDomain,
    handleNodeClick,
  };
}
