/*!
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
import { useToken } from "@chakra-ui/react";
import { ReactFlow, Controls, Background, MiniMap, type Node as ReactFlowNode } from "@xyflow/react";
import "@xyflow/react/dist/style.css";
import { useParams } from "react-router-dom";
import { useLocalStorage } from "usehooks-ts";

import type { AssetResponse } from "openapi/requests/types.gen";
import type { Direction } from "src/components/Graph/DirectionDropdown";
import { DownloadButton } from "src/components/Graph/DownloadButton";
import { edgeTypes, nodeTypes } from "src/components/Graph/graphTypes";
import type { CustomNodeProps } from "src/components/Graph/reactflowUtils";
import { useGraphLayout } from "src/components/Graph/useGraphLayout";
import { directionKey } from "src/constants/localStorage";
import { useColorMode } from "src/context/colorMode";
import { useDependencyGraph } from "src/queries/useDependencyGraph";
import { getReactFlowThemeStyle } from "src/theme";

export const AssetGraph = ({
  asset,
  dependencyType = "scheduling",
}: {
  readonly asset?: AssetResponse;
  readonly dependencyType?: "data" | "scheduling";
}) => {
  const { assetId } = useParams();
  const { colorMode = "light" } = useColorMode();

  // Fetch graph data from backend - filtering is done server-side
  const { data: graphData = { edges: [], nodes: [] } } = useDependencyGraph(`asset:${assetId}`, {
    dependencyType,
  });

  const [direction] = useLocalStorage<Direction>(directionKey(assetId ?? ""), "RIGHT");

  const { data: layoutData } = useGraphLayout({
    ...graphData,
    direction,
    openGroupIds: [],
  });

  const [selectedDarkColor, selectedLightColor] = useToken("colors", ["bg.muted", "bg.emphasized"]);

  const selectedColor = colorMode === "dark" ? selectedDarkColor : selectedLightColor;

  const nodes = layoutData?.nodes.map((node) =>
    node.id === `asset:${assetId}` ? { ...node, data: { ...node.data, isSelected: true } } : node,
  );

  const edges = (layoutData?.edges ?? []).map((edge) => ({
    ...edge,
    data: {
      ...edge.data,
      rest: {
        ...edge.data?.rest,
        edgeType: dependencyType,
        isSelected: `asset:${asset?.id}` === edge.source || `asset:${asset?.id}` === edge.target,
      },
    },
  }));

  return (
    <ReactFlow
      colorMode={colorMode}
      defaultEdgeOptions={{ zIndex: 1 }}
      edges={edges}
      edgeTypes={edgeTypes}
      // Fit view to selected task or the whole graph on render
      fitView
      maxZoom={1.5}
      minZoom={0.25}
      nodes={nodes}
      nodesDraggable={false}
      nodeTypes={nodeTypes}
      onlyRenderVisibleElements
      style={getReactFlowThemeStyle(colorMode)}
    >
      <Background />
      <Controls showInteractive={false} />
      <MiniMap
        nodeStrokeColor={(node: ReactFlowNode<CustomNodeProps>) =>
          node.data.isSelected && selectedColor !== undefined ? selectedColor : ""
        }
        nodeStrokeWidth={15}
        pannable
        zoomable
      />
      <DownloadButton name={asset?.name ?? asset?.uri ?? "asset"} />
    </ReactFlow>
  );
};
