react flow

import React, { useState, useCallback, useEffect, useRef } from "react";
import Layout from "@/components/layout";
import { Combobox } from "@/components/ui/combobox";
import {
  ReactFlow,
  MiniMap,
  Controls,
  Background,
  useNodesState,
  useEdgesState,
  addEdge,
  Handle,
  Position,
  ReactFlowProvider,
  getBezierPath,
} from "@xyflow/react";
import Spinner from "@/components/spinner";
import { getCookie } from "cookies-next";
import "@xyflow/react/dist/style.css";
import toast, { Toaster } from "react-hot-toast";
import { X, Image, List, Type, Database } from "lucide-react";
import axios from "../../../utils/axiosInstance";
import { useRouter } from "next/router";
import { uploadFileToS3 } from "../../../utils/mediaupload";
import { generateHandleId } from "../../../utils/handleIds";

const CustomEdge = ({
  id,
  sourceX,
  sourceY,
  targetX,
  targetY,
  sourcePosition,
  targetPosition,
  style = {},
  data,
  markerEnd,
}) => {
  const [edgePath, labelX, labelY] = getBezierPath({
    sourceX,
    sourceY,
    sourcePosition,
    targetX,
    targetY,
    targetPosition,
  });

  const [isHovered, setIsHovered] = useState(false);

  // Ensure we're using the onDelete callback from props.data
  const handleEdgeDelete = () => {
    if (data?.onDelete) {
      data.onDelete(id);
    }
  };

  return (
    <>
      <path
        id={id}
        style={{
          ...style,
          strokeWidth: 2,
          stroke: "#6366f1",
        }}
        className="react-flow__edge-path hover:stroke-indigo-400"
        d={edgePath}
        markerEnd={markerEnd}
      />
      <g
        transform={`translate(${labelX} ${labelY})`}
        onMouseEnter={() => setIsHovered(true)}
        onMouseLeave={() => setIsHovered(false)}
      >
        {/* Make the entire circle clickable */}
        <circle
          r="18"
          className={`
            cursor-pointer
            transition-all duration-200 
            ${
              isHovered
                ? "fill-red-50 stroke-red-300"
                : "fill-white stroke-gray-200"
            }
          `}
          strokeWidth="1.5"
          onClick={handleEdgeDelete} // Make sure this is called
          style={{ pointerEvents: "all" }} // Ensure clicks are captured
        />

        {/* X icon */}
        <g
          className={`
            transform transition-transform duration-200
            ${isHovered ? "scale-110" : "scale-100"}
          `}
          style={{ pointerEvents: "none" }} // Prevent X from capturing clicks
        >
          <path
            d="M-6 -6 L6 6 M-6 6 L6 -6"
            className={`
              transition-all duration-200
              ${isHovered ? "stroke-red-500" : "stroke-gray-400"}
            `}
            strokeWidth="2.5"
            strokeLinecap="round"
          />
        </g>

        {/* Ripple effect on hover */}
        {isHovered && (
          <circle
            r="18"
            className="fill-none stroke-red-200 animate-ping"
            strokeWidth="2"
            opacity="0.5"
            style={{ pointerEvents: "none" }} // Prevent ripple from capturing clicks
          />
        )}
      </g>
    </>
  );
};

const NodeTypeDropdown = ({ options, onSelect, onCancel, position }) => {
  const nodeIcons = {
    "Text + Button": Type,
    Media: Image,
    List: List,
    Attribute: Database,
  };

  return (
    <div
      className="absolute bg-white rounded-xl shadow-2xl border border-gray-200 p-4 z-50 w-[300px]"
      style={{
        top: position.y,
        left: position.x,
        transform: "translate(-50%, -50%)",
      }}
    >
      <div className="flex justify-between items-center mb-4">
        <h3 className="text-lg font-semibold text-gray-800">Select Action</h3>
        <button
          onClick={onCancel}
          className="text-gray-500 hover:text-gray-700 transition-colors"
          title="Cancel"
        >
          <X className="w-6 h-6" />
        </button>
      </div>

      <div className="grid grid-cols-2 gap-3">
        {options.map((option) => {
          const Icon = nodeIcons[option];
          return (
            <button
              key={option}
              onClick={() => onSelect(option)}
              className="
                flex flex-col items-center justify-center 
                p-4 rounded-lg 
                hover:bg-indigo-50 
                border border-transparent 
                hover:border-indigo-200 
                transition-all 
                group
              "
            >
              <Icon
                className="
                  w-8 h-8 mb-2 
                  text-gray-500 
                  group-hover:text-indigo-600 
                  transition-colors
                "
              />
              <span
                className="
                text-sm font-medium 
                text-gray-700 
                group-hover:text-indigo-700
              "
              >
                {option}
              </span>
            </button>
          );
        })}
      </div>
    </div>
  );
};

// Common Header Component for Nodes

const NodeHeader = ({
  type,
  onDelete,
  canDelete = true,
  messageNumber = null,
}) => (
  <div className="flex items-center justify-between mb-3">
    <div className="flex items-center gap-3">
      {/* WhatsApp Icon */}
      <svg
        viewBox="0 0 24 24"
        className="w-6 h-6 text-[#25D366] flex-shrink-0"
        fill="currentColor"
      >
        <path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z" />
      </svg>

      {/* Node Type */}
      <span className="text-[15px] font-medium text-gray-700">{type}</span>

      {/* Message Number Badge */}
      {messageNumber && (
        <span className="bg-indigo-100 text-indigo-700 text-sm font-medium px-3 py-0.5 rounded-full">
          Message {messageNumber}
        </span>
      )}
    </div>

    {/* Delete Button */}
    {canDelete && (
      <button
        onClick={onDelete}
        className="text-gray-400 hover:text-red-500 transition-colors"
        title="Delete node"
      >
        <svg
          xmlns="http://www.w3.org/2000/svg"
          className="h-5 w-5"
          viewBox="0 0 20 20"
          fill="currentColor"
        >
          <path
            fillRule="evenodd"
            d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
            clipRule="evenodd"
          />
        </svg>
      </button>
    )}
  </div>
);

// Button Component with Delete Option
const ButtonInput = ({
  button,
  onChange,
  onDelete,
  handleId,
  showHandle = true,
}) => (
  <div className="relative flex items-center gap-2">
    <input
      type="text"
      value={button.label}
      onChange={(e) => onChange(e.target.value)}
      className="w-full p-2 border rounded-md text-sm"
      placeholder="Button text"
    />
    <button
      onClick={onDelete}
      className="text-gray-400 hover:text-red-500 transition-colors"
      title="Delete button"
    >
      <svg
        xmlns="http://www.w3.org/2000/svg"
        className="h-5 w-5"
        viewBox="0 0 20 20"
        fill="currentColor"
      >
        <path
          fillRule="evenodd"
          d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
          clipRule="evenodd"
        />
      </svg>
    </button>
    {showHandle && (
      <Handle
        type="source"
        position={Position.Right}
        id={handleId}
        style={{
          backgroundColor: "indigo",
          width: "13px",
          height: "13px",
          borderRadius: "50%",
          right: "-20px",
        }}
      />
    )}
  </div>
);

// TriggerNode component
const TriggerNode = ({ data, id }) => {
  const [keywords, setKeywords] = useState(data.keywords || ["Hi"]);

  const handleAddKeyword = () => {
    const newKeywords = [...keywords, "New Keyword"];
    setKeywords(newKeywords);
    data.onKeywordsUpdate?.(id, newKeywords);
  };

  const handleKeywordChange = (index, value) => {
    const newKeywords = keywords.map((kw, i) => (i === index ? value : kw));
    setKeywords(newKeywords);
    data.onKeywordsUpdate?.(id, newKeywords);
  };

  const handleDeleteKeyword = (index) => {
    const newKeywords = keywords.filter((_, i) => i !== index);
    setKeywords(newKeywords);
    data.onKeywordsUpdate?.(id, newKeywords);
  };

  return (
    <div className="bg-white rounded-lg shadow-lg p-4 w-[300px] relative">
      <NodeHeader type="Starting Step" canDelete={false} />

      <div className="bg-gray-50 rounded-lg p-3 space-y-3">
        {/* Add descriptive text */}
        <div className="text-xs text-gray-600 mb-3">
          Start the flow if the user's message matches any of these keywords:
        </div>

        {keywords.map((keyword, index) => (
          <div key={index} className="relative flex items-center gap-2">
            <input
              type="text"
              value={keyword}
              onChange={(e) => handleKeywordChange(index, e.target.value)}
              className="w-full p-2 border rounded-md text-sm"
              placeholder="Enter keyword"
            />
            <button
              onClick={() => handleDeleteKeyword(index)}
              className="text-gray-400 hover:text-red-500 transition-colors"
              title="Delete keyword"
            >
              <svg
                xmlns="http://www.w3.org/2000/svg"
                className="h-5 w-5"
                viewBox="0 0 20 20"
                fill="currentColor"
              >
                <path
                  fillRule="evenodd"
                  d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
                  clipRule="evenodd"
                />
              </svg>
            </button>
          </div>
        ))}

        <button
          onClick={handleAddKeyword}
          className="text-indigo-500 hover:text-indigo-700 text-sm"
        >
          + Add Keyword
        </button>

        {/* Add note for additional context */}
        {/* <div className="text-xs text-gray-500 mt-2 italic">
          Note: The flow will start automatically when a user sends any of these
          keywords.
        </div> */}
      </div>

      {/* Bottom handle for connecting to other nodes */}
      <Handle
        type="source"
        position={Position.Right}
        style={{
          backgroundColor: "indigo",
          width: "13px",
          height: "13px",
          borderRadius: "50%",
        }}
      />
    </div>
  );
};

// Text + Button Node Component
const TextButtonNode = ({ data, id }) => {
  const [content, setContent] = useState(data.content || "");
  const [buttons, setButtons] = useState(
    data.buttons?.length > 0
      ? data.buttons
      : [
          {
            label: "Button 1",
            handleId: generateHandleId("btn", Date.now(), 0),
          },
        ]
  );

  // In TextButtonNode component
  useEffect(() => {
    if (!data.buttons || data.buttons.length === 0) {
      const defaultButton = {
        label: "Button 1",
        handleId: generateHandleId("btn", Date.now(), 0),
      };
      data.onButtonsUpdate?.(id, [defaultButton]);
    }
  }, []);

  const handleContentChange = (value) => {
    // Limit content to 1024 characters (WhatsApp body text limit)
    if (value.length <= 1024) {
      setContent(value);
      data.onContentUpdate?.(id, value);
    }
  };

  const handleAddButton = () => {
    if (buttons.length < 3) {
      const newButton = {
        label: "New Button",
        handleId: generateHandleId("btn", Date.now(), buttons.length),
      };
      const updatedButtons = [...buttons, newButton];
      setButtons(updatedButtons);
      data.onButtonsUpdate?.(id, updatedButtons);
    }
  };

  const handleButtonTextChange = (index, value) => {
    // Limit button text to 20 characters
    if (value.length <= 20) {
      const newButtons = buttons.map((btn, i) =>
        i === index ? { ...btn, label: value } : btn
      );
      setButtons(newButtons);
      data.onButtonsUpdate?.(id, newButtons);
    }
  };

  const handleDeleteButton = (index) => {
    if (buttons.length <= 1) {
      toast.error("At least one button is required");
      return;
    }
    const newButtons = buttons.filter((_, i) => i !== index);
    setButtons(newButtons);
    data.onButtonsUpdate?.(id, newButtons);
  };

  return (
    <div className="bg-white rounded-lg shadow-lg p-4 w-[300px] relative">
      <Handle
        type="target"
        position={Position.Left}
        style={{
          backgroundColor: "indigo",
          width: "13px",
          height: "13px",
          borderRadius: "50%",
        }}
      />

      <NodeHeader
        type="Text + Button"
        onDelete={data.onDelete}
        messageNumber={data.messageNumber}
      />

      <div className="bg-gray-50 rounded-lg p-3 space-y-3">
        <div>
          <textarea
            value={content}
            onChange={(e) => handleContentChange(e.target.value)}
            placeholder="Enter your message... (max 1024 chars)"
            className="w-full p-2 border rounded-md text-sm min-h-[90px] resize-none"
          />
          <div className="text-xs text-gray-500 text-right">
            {content.length}/1024 characters
          </div>
        </div>

        {buttons.map((btn, index) => (
          <div key={index} className="relative flex items-center gap-2">
            <input
              type="text"
              value={btn.label}
              onChange={(e) => handleButtonTextChange(index, e.target.value)}
              className="w-full p-2 border rounded-md text-sm"
              placeholder="Button text (max 20 chars)"
            />
            <div className="text-xs text-gray-500 mr-2">
              {btn.label.length}/20
            </div>
            <button
              onClick={() => handleDeleteButton(index)}
              className="text-gray-400 hover:text-red-500 transition-colors"
              title="Delete button"
            >
              <svg
                xmlns="http://www.w3.org/2000/svg"
                className="h-5 w-5"
                viewBox="0 0 20 20"
                fill="currentColor"
              >
                <path
                  fillRule="evenodd"
                  d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
                  clipRule="evenodd"
                />
              </svg>
            </button>
            <Handle
              type="source"
              position={Position.Right}
              id={btn.handleId}
              style={{
                backgroundColor: "indigo",
                width: "13px",
                height: "13px",
                borderRadius: "50%",
                right: "-20px",
              }}
            />
          </div>
        ))}

        <button
          onClick={handleAddButton}
          className="text-indigo-500 hover:text-indigo-700 text-sm"
          disabled={buttons.length >= 3}
        >
          + Add Button {buttons.length}/3
        </button>
      </div>
    </div>
  );
};

// Media Node Component
const MediaNode = ({ data, id }) => {
  const [content, setContent] = useState(data.content || "");
  const [mediaUrl, setMediaUrl] = useState(data.mediaUrl || "");
  const [mediaType, setMediaType] = useState(data.mediaType || "");
  const [fileName, setFileName] = useState(data.fileName || "");
  const [buttons, setButtons] = useState(
    data.buttons?.length > 0
      ? data.buttons
      : [
          {
            label: "Button 1",
            handleId: generateHandleId("btn", Date.now(), 0),
          },
        ]
  );
  const [isLoading, setIsLoading] = useState(false);
  const [uploadedId, setUploadedId] = useState(data.uploadedId || "");

  useEffect(() => {
    // If there are no buttons in the parent data, update it with the default button
    if (!data.buttons || data.buttons.length === 0) {
      const defaultButton = {
        label: "Button 1",
        handleId: generateHandleId("btn", Date.now(), 0),
      };
      data.onButtonsUpdate?.(id, [defaultButton]);
    }
  }, []);

  const getMediaType = (file) => {
    if (file.type.startsWith("image/")) return "image";
    if (file.type.startsWith("video/")) return "video";
    return "document";
  };

  const handleMediaUpload = async (event) => {
    const file = event.target.files[0];

    if (file) {
      setIsLoading(true);

      try {
        // Upload to S3
        const result = await uploadFileToS3(
          file,
          `whatsapp-media-${id}`, // Using node id to make it unique
          "whatsapp/automation"
        );

        if (result.success) {
          let mediaPreviewUrl = null;
          // Create preview URL for images and videos
          if (result.category === "image" || result.category === "video") {
            mediaPreviewUrl = result.url; // Use the S3 URL directly
          }

          // Set all the state values
          setUploadedId(result.url); // Store S3 URL instead of WhatsApp media ID
          setFileName(result.fileName);
          setMediaUrl(mediaPreviewUrl || result.url);
          setMediaType(result.category);

          // Update node data with all fields
          data.onMediaUpdate?.(
            id,
            result.url, // Use S3 URL
            result.category,
            result.url, // Using S3 URL as ID
            result.fileName
          );

          toast.success("Media uploaded successfully");
        }
      } catch (error) {
        console.error("File upload failed:", error);
        toast.error(
          error.message || "Failed to upload media. Please try again."
        );
      } finally {
        setIsLoading(false);
      }
    }
  };

  // const handleMediaUpload = async (event) => {
  //   const file = event.target.files[0];

  //   if (file) {
  //     setIsLoading(true);
  //     const formData = new FormData();
  //     formData.append("file", file);
  //     formData.append("messaging_product", "whatsapp");

  //     const type = getMediaType(file);
  //     formData.append("type", type);

  //     const access_token = getCookie("at");
  //     const wb_phone_number_id = getCookie("pni");

  //     try {
  //       const response = await fetch(
  //         `https://graph.facebook.com/v21.0/${wb_phone_number_id}/media`,
  //         {
  //           method: "POST",
  //           body: formData,
  //           headers: {
  //             Authorization: `Bearer ${access_token}`,
  //           },
  //         }
  //       );

  //       if (response.ok) {
  //         const responseData = await response.json();
  //         console.log(responseData, "this is media id data");

  //         let mediaPreviewUrl = null;
  //         // Create preview URL for images and videos
  //         if (type === "image" || type === "video") {
  //           mediaPreviewUrl = URL.createObjectURL(file);
  //         }

  //         // Set all the state values
  //         setUploadedId(responseData.id);
  //         setFileName(file.name);
  //         setMediaUrl(mediaPreviewUrl || "");
  //         setMediaType(type);

  //         // Update node data with all fields
  //         data.onMediaUpdate?.(
  //           id,
  //           mediaPreviewUrl, // Use the mediaPreviewUrl we just created
  //           type,
  //           responseData.id, // Pass the uploaded ID
  //           file.name // Pass the file name
  //         );
  //       } else {
  //         const errorData = await response.json();
  //         toast.error(errorData.error.error_data.details);
  //       }
  //     } catch (error) {
  //       console.error("File upload failed:", error);
  //       toast.error("Failed to upload media. Please try again.");
  //     } finally {
  //       setIsLoading(false);
  //     }
  //   }
  // };

  const renderMediaPreview = () => {
    if (isLoading) {
      return (
        <div className="flex items-center justify-center p-4">
          <Spinner />
          <span className="ml-2 text-sm text-gray-600">Uploading...</span>
        </div>
      );
    }

    if (mediaType === "document") {
      return (
        <div className="relative w-full bg-white p-4 rounded-lg border">
          <div className="flex items-center max-w-full">
            <svg
              className="w-8 h-8 text-gray-500 flex-shrink-0"
              fill="none"
              stroke="currentColor"
              viewBox="0 0 24 24"
              xmlns="http://www.w3.org/2000/svg"
            >
              <path
                strokeLinecap="round"
                strokeLinejoin="round"
                strokeWidth={2}
                d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"
              />
            </svg>
            <div className="ml-3 min-w-0 flex-1">
              <p className="text-sm font-medium text-gray-900 truncate max-w-[180px]">
                {fileName}
              </p>
              <p className="text-sm text-gray-500">Document</p>
            </div>
          </div>
          <button
            onClick={() => {
              setMediaUrl("");
              setMediaType("");
              setUploadedId("");
              setFileName("");
            }}
            className="absolute top-1 right-1 bg-red-500 text-white rounded-full w-6 h-6 flex items-center justify-center text-sm hover:bg-red-600"
          >
            ×
          </button>
        </div>
      );
    }

    if (mediaUrl) {
      return (
        <div className="relative w-full">
          {mediaType === "image" ? (
            <img
              src={mediaUrl}
              alt="Uploaded media"
              className="max-w-full h-auto rounded"
            />
          ) : (
            <video
              src={mediaUrl}
              controls
              className="max-w-full h-auto rounded"
            />
          )}
          <button
            onClick={() => {
              setMediaUrl("");
              setMediaType("");
              setUploadedId("");
              setFileName("");
            }}
            className="absolute top-1 right-1 bg-red-500 text-white rounded-full w-6 h-6 flex items-center justify-center text-sm hover:bg-red-600"
          >
            ×
          </button>
        </div>
      );
    }

    return (
      <div className="text-center">
        <input
          type="file"
          accept="image/*,video/*,application/*,.pdf,.doc,.docx,.xls,.xlsx"
          onChange={handleMediaUpload}
          className="hidden"
          id={`media-upload-${id}`}
        />
        <label
          htmlFor={`media-upload-${id}`}
          className="cursor-pointer bg-indigo-500 text-white px-4 py-2 rounded-md hover:bg-indigo-600 inline-block"
        >
          Upload Media
        </label>
      </div>
    );
  };

  // Rest of the component remains the same as in the previous implementation
  const handleContentChange = (value) => {
    // Limit content to 1024 characters
    if (value.length <= 1024) {
      setContent(value);
      data.onContentUpdate?.(id, value);
    }
  };

  const handleAddButton = () => {
    if (buttons.length < 3) {
      const newButton = {
        label: "New Button",
        handleId: generateHandleId("btn", Date.now(), buttons.length),
      };
      const updatedButtons = [...buttons, newButton];
      setButtons(updatedButtons);
      data.onButtonsUpdate?.(id, updatedButtons);
    }
  };

  const handleButtonTextChange = (index, value) => {
    // Limit button text to 20 characters
    if (value.length <= 20) {
      const newButtons = buttons.map((btn, i) =>
        i === index ? { ...btn, label: value } : btn
      );
      setButtons(newButtons);
      data.onButtonsUpdate?.(id, newButtons);
    }
  };

  const handleDeleteButton = (index) => {
    if (buttons.length <= 1) {
      toast.error("At least one button is required");
      return;
    }
    const newButtons = buttons.filter((_, i) => i !== index);
    setButtons(newButtons);
    data.onButtonsUpdate?.(id, newButtons);
  };

  return (
    <div className="bg-white rounded-lg shadow-lg p-4 w-[300px] relative">
      <Handle
        type="target"
        position={Position.Left}
        style={{
          backgroundColor: "indigo",
          width: "13px",
          height: "13px",
          borderRadius: "50%",
        }}
      />

      <NodeHeader
        type="Media"
        onDelete={data.onDelete}
        messageNumber={data.messageNumber}
      />

      <div className="bg-gray-50 rounded-lg p-3 space-y-3">
        <div className="flex justify-center items-center bg-gray-100 border-2 border-dashed border-gray-300 rounded-lg p-4">
          {renderMediaPreview()}
        </div>

        <div>
          <textarea
            value={content}
            onChange={(e) => handleContentChange(e.target.value)}
            placeholder="Enter your message... (max 1024 chars)"
            className="w-full p-2 border rounded-md text-sm min-h-[60px] resize-none"
          />
          <div className="text-xs text-gray-500 text-right">
            {content.length}/1024 characters
          </div>
        </div>

        {buttons.map((btn, index) => (
          <div key={index} className="relative flex items-center gap-2">
            <input
              type="text"
              value={btn.label}
              onChange={(e) => handleButtonTextChange(index, e.target.value)}
              className="w-full p-2 border rounded-md text-sm"
              placeholder="Button text (max 20 chars)"
            />
            <div className="text-xs text-gray-500 mr-2">
              {btn.label.length}/20
            </div>
            <button
              onClick={() => handleDeleteButton(index)}
              className="text-gray-400 hover:text-red-500 transition-colors"
              title="Delete button"
            >
              <svg
                xmlns="http://www.w3.org/2000/svg"
                className="h-5 w-5"
                viewBox="0 0 20 20"
                fill="currentColor"
              >
                <path
                  fillRule="evenodd"
                  d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
                  clipRule="evenodd"
                />
              </svg>
            </button>
            <Handle
              type="source"
              position={Position.Right}
              id={btn.handleId}
              style={{
                backgroundColor: "indigo",
                width: "13px",
                height: "13px",
                borderRadius: "50%",
                right: "-20px",
              }}
            />
          </div>
        ))}

        <button
          onClick={handleAddButton}
          className="text-indigo-500 hover:text-indigo-700 text-sm"
          disabled={buttons.length >= 3}
        >
          + Add Button {buttons.length}/3
        </button>
      </div>
    </div>
  );
};

const ListNode = ({ data, id }) => {
  const [content, setContent] = useState(data.content || "");
  const [buttonText, setButtonText] = useState(data.buttonText || "Options");
  // Default section and row
  const defaultSection = {
    title: "Section 1",
    rows: [
      {
        id: generateHandleId("list-row", Date.now(), "0-0"),
        title: "Option 1",
        description: "Description for Option 1 (Optional)",
      },
    ],
  };

  const [sections, setSections] = useState(
    data.sections?.length > 0 ? data.sections : [defaultSection]
  );

  // Add this useEffect to sync with parent on mount
  useEffect(() => {
    if (!data.sections || data.sections.length === 0) {
      data.onSectionsUpdate?.(id, [defaultSection]);
    }
  }, []); // Empty dependency array means this runs once on mount

  // Helper function to count total rows across all sections
  const getTotalRowCount = useCallback(() => {
    return sections.reduce((total, section) => total + section.rows.length, 0);
  }, [sections]);

  // Content update handler
  const handleContentChange = (value) => {
    if (value.length <= 4096) {
      setContent(value);
      data.onContentUpdate?.(id, value);
    }
  };

  // Button text update handler
  const handleButtonTextChange = (value) => {
    if (value.length <= 20) {
      setButtonText(value);
      data.onButtonTextUpdate?.(id, value);
    }
  };

  // Section handlers
  const handleSectionTitleChange = (sectionIndex, newTitle) => {
    const updatedSections = sections.map((section, index) => {
      if (index === sectionIndex) {
        return { ...section, title: newTitle };
      }
      return section;
    });
    setSections(updatedSections);
    data.onSectionsUpdate?.(id, updatedSections);
  };

  const handleDeleteSection = (sectionIndex) => {
    const totalRowsAfterDeletion =
      getTotalRowCount() - sections[sectionIndex].rows.length;

    if (totalRowsAfterDeletion === 0) {
      toast.error("Must maintain at least one row in total");
      return;
    }

    const updatedSections = sections.filter(
      (_, index) => index !== sectionIndex
    );
    setSections(updatedSections);
    data.onSectionsUpdate?.(id, updatedSections);
  };

  const handleAddSection = () => {
    if (sections.length >= 10) {
      toast.error("Maximum of 10 sections allowed");
      return;
    }

    if (getTotalRowCount() + 1 > 10) {
      toast.error("Maximum of 10 total rows allowed across all sections");
      return;
    }

    const newSection = {
      title: `Section ${sections.length + 1}`,
      rows: [
        {
          id: generateHandleId("list-row", Date.now(), `${sections.length}-0`),
          title: "New Option",
          description: "Description for new option (Optional)",
        },
      ],
    };
    const updatedSections = [...sections, newSection];
    setSections(updatedSections);
    data.onSectionsUpdate?.(id, updatedSections);
  };

  // Row handlers
  const handleRowChange = (sectionIndex, rowIndex, field, value) => {
    const updatedSections = sections.map((section, secIndex) => {
      if (secIndex === sectionIndex) {
        const updatedRows = section.rows.map((row, rowIdx) => {
          if (rowIdx === rowIndex) {
            return { ...row, [field]: value };
          }
          return row;
        });
        return { ...section, rows: updatedRows };
      }
      return section;
    });
    setSections(updatedSections);
    data.onSectionsUpdate?.(id, updatedSections);
  };

  const handleDeleteRow = (sectionIndex, rowIndex) => {
    if (getTotalRowCount() <= 1) {
      toast.error("At least one row is required in total");
      return;
    }

    const updatedSections = sections.map((section, secIndex) => {
      if (secIndex === sectionIndex) {
        const updatedRows = section.rows.filter((_, idx) => idx !== rowIndex);
        return {
          ...section,
          rows: updatedRows.length > 0 ? updatedRows : section.rows,
        };
      }
      return section;
    });
    setSections(updatedSections);
    data.onSectionsUpdate?.(id, updatedSections);
  };

  const handleAddRow = (sectionIndex) => {
    if (getTotalRowCount() >= 10) {
      toast.error("Maximum of 10 total rows allowed across all sections");
      return;
    }

    const updatedSections = sections.map((section, index) => {
      if (index === sectionIndex) {
        const newRow = {
          id: generateHandleId(
            "list-row",
            Date.now(),
            `${sectionIndex}-${section.rows.length}`
          ),
          title: "New Option",
          description: "Description for new option (Optional)",
        };
        return {
          ...section,
          rows: [...section.rows, newRow],
        };
      }
      return section;
    });

    setSections(updatedSections);
    data.onSectionsUpdate?.(id, updatedSections);
  };

  return (
    <div className="bg-white rounded-lg shadow-lg p-4 w-[350px] relative">
      <Handle
        type="target"
        position={Position.Left}
        style={{
          backgroundColor: "#4F46E5",
          width: "13px",
          height: "13px",
          borderRadius: "50%",
        }}
      />

      <NodeHeader
        type="List"
        onDelete={data.onDelete}
        messageNumber={data.messageNumber}
      />

      <div className="bg-gray-50 rounded-lg p-3 space-y-3">
        {/* Content Input */}
        <div>
          <textarea
            value={content}
            onChange={(e) => handleContentChange(e.target.value)}
            placeholder="Message body (max 4096 chars)"
            className="w-full p-2 border rounded-md text-sm min-h-[90px] resize-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
            maxLength={4096}
          />
          <div className="text-xs text-gray-500 text-right">
            {content.length}/4096 characters
          </div>
        </div>

        {/* Button Text Input */}
        <div>
          <input
            type="text"
            value={buttonText}
            onChange={(e) => handleButtonTextChange(e.target.value)}
            className="w-full p-2 border rounded-md text-sm focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
            placeholder="Button text (max 20 chars)"
            maxLength={20}
          />
          <div className="text-xs text-gray-500 text-right">
            {buttonText.length}/20 characters
          </div>
        </div>

        {/* Counters */}
        <div className="flex justify-between text-sm text-gray-600 mb-2">
          <span>Sections: {sections.length}/10</span>
          <span>Total Rows: {getTotalRowCount()}/10</span>
        </div>

        {/* Sections */}
        {sections.map((section, sectionIndex) => (
          <div key={sectionIndex} className="border rounded-lg p-2 bg-white">
            {/* Section Header */}
            <div className="flex justify-between items-center mb-2">
              <div className="flex-1 mr-2">
                <input
                  type="text"
                  value={section.title}
                  onChange={(e) => {
                    if (e.target.value.length <= 24) {
                      handleSectionTitleChange(sectionIndex, e.target.value);
                    }
                  }}
                  className="w-full p-2 border rounded-md text-sm focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
                  placeholder="Section title (max 24 chars)"
                  maxLength={24}
                />
                <div className="text-xs text-gray-500 mt-1">
                  {section.title.length}/24 characters
                </div>
              </div>
              <button
                onClick={() => handleDeleteSection(sectionIndex)}
                className="text-red-500 hover:text-red-700 p-1 rounded-full hover:bg-red-50"
                title="Delete Section"
              >
                <svg
                  className="w-5 h-5"
                  fill="none"
                  stroke="currentColor"
                  viewBox="0 0 24 24"
                >
                  <path
                    strokeLinecap="round"
                    strokeLinejoin="round"
                    strokeWidth={2}
                    d="M6 18L18 6M6 6l12 12"
                  />
                </svg>
              </button>
            </div>

            {/* Rows */}
            {section.rows.map((row, rowIndex) => (
              <div
                key={row.id}
                className="mb-2 p-2 border rounded-lg bg-gray-50 relative"
              >
                <div className="flex mb-2 items-center">
                  <input
                    type="text"
                    value={row.title}
                    onChange={(e) => {
                      if (e.target.value.length <= 24) {
                        handleRowChange(
                          sectionIndex,
                          rowIndex,
                          "title",
                          e.target.value
                        );
                      }
                    }}
                    className="w-full p-2 border rounded-md text-sm mr-2 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
                    placeholder="Row title (max 24 chars)"
                    maxLength={24}
                  />
                  <div className="text-xs text-gray-500 mr-2">
                    {row.title.length}/24
                  </div>
                  <button
                    onClick={() => handleDeleteRow(sectionIndex, rowIndex)}
                    className="text-red-500 hover:text-red-700 p-1 rounded-full hover:bg-red-50"
                    title="Delete Row"
                  >
                    <svg
                      className="w-5 h-5"
                      fill="none"
                      stroke="currentColor"
                      viewBox="0 0 24 24"
                    >
                      <path
                        strokeLinecap="round"
                        strokeLinejoin="round"
                        strokeWidth={2}
                        d="M6 18L18 6M6 6l12 12"
                      />
                    </svg>
                  </button>
                </div>
                <div>
                  <input
                    type="text"
                    value={row.description}
                    onChange={(e) => {
                      if (e.target.value.length <= 72) {
                        handleRowChange(
                          sectionIndex,
                          rowIndex,
                          "description",
                          e.target.value
                        );
                      }
                    }}
                    className="w-full p-2 border rounded-md text-sm focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
                    placeholder="Row description (max 72 chars)"
                    maxLength={72}
                  />
                  <div className="text-xs text-gray-500 text-right">
                    {row.description.length}/72 characters
                  </div>
                </div>
                <Handle
                  type="source"
                  position={Position.Right}
                  id={row.id}
                  style={{
                    backgroundColor: "#4F46E5",
                    width: "13px",
                    height: "13px",
                    borderRadius: "50%",
                    right: "-20px",
                    top: "50%",
                    transform: "translateY(-50%)",
                  }}
                />
              </div>
            ))}

            {/* Add Row Button */}
            <button
              onClick={() => handleAddRow(sectionIndex)}
              className={`text-indigo-600 hover:text-indigo-700 text-sm mt-2 flex items-center ${
                getTotalRowCount() >= 10 ? "opacity-50 cursor-not-allowed" : ""
              }`}
              disabled={getTotalRowCount() >= 10}
            >
              <svg
                className="w-4 h-4 mr-1"
                fill="none"
                stroke="currentColor"
                viewBox="0 0 24 24"
              >
                <path
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  strokeWidth={2}
                  d="M12 4v16m8-8H4"
                />
              </svg>
              Add Row
            </button>
          </div>
        ))}

        {/* Add Section Button */}
        <button
          onClick={handleAddSection}
          className={`text-indigo-600 hover:text-indigo-700 text-sm flex items-center justify-center w-full py-2 border-2 border-dashed border-indigo-200 rounded-lg hover:bg-indigo-50 transition-colors ${
            sections.length >= 10 || getTotalRowCount() >= 10
              ? "opacity-50 cursor-not-allowed"
              : ""
          }`}
          disabled={sections.length >= 10 || getTotalRowCount() >= 10}
        >
          <svg
            className="w-4 h-4 mr-1"
            fill="none"
            stroke="currentColor"
            viewBox="0 0 24 24"
          >
            <path
              strokeLinecap="round"
              strokeLinejoin="round"
              strokeWidth={2}
              d="M12 4v16m8-8H4"
            />
          </svg>
          Add Section
        </button>
      </div>
    </div>
  );
};

// Attribute Node Component
const AttributeNode = ({ data, id }) => {
  const [attributes, setAttributes] = useState([]);
  const [selectedAttribute, setSelectedAttribute] = useState(
    data.attribute1 || ""
  );
  const [predefinedValue, setPredefinedValue] = useState(data.attribute2 || "");

  // Fetch attributes only once when the component is first created
  useEffect(() => {
    const fetchAttributes = async () => {
      try {
        const response = await axios.get(
          process.env.NEXT_PUBLIC_BASE_URL + "/whatsapp/attribute/"
        );
        setAttributes(response.data?.results || []);
      } catch (err) {
        toast.error("Failed to load attributes");
      }
    };

    // Only fetch if attributes haven't been loaded yet
    if (attributes.length === 0) {
      fetchAttributes();
    }
  }, []);

  // Effect to update predefined value based on source node's data
  useEffect(() => {
    // Check for button text from various node types
    if (data.sourceButtonText) {
      setPredefinedValue(data.sourceButtonText);
      data.onAttributeUpdate?.(id, "attribute2", data.sourceButtonText);
    }
  }, [data.sourceButtonText]);

  const handleAttributeChange = (value) => {
    setSelectedAttribute(value);
    data.onAttributeUpdate?.(id, "attribute1", value);
  };

  const handlePredefinedValueChange = (value) => {
    setPredefinedValue(value);
    data.onAttributeUpdate?.(id, "attribute2", value);
  };

  return (
    <div className="bg-white rounded-lg shadow-lg p-4 w-[350px] relative">
      {/* Left handle for incoming connections */}

      <NodeHeader
        type="Attribute"
        onDelete={data.onDelete}
        messageNumber={data.messageNumber}
      />
      <Handle
        type="target"
        position={Position.Left}
        style={{
          backgroundColor: "indigo",
          width: "13px",
          height: "13px",
          borderRadius: "50%",
          left: "-6px",
        }}
      />

      {/* Right handle for outgoing connections */}
      <Handle
        type="source"
        position={Position.Right}
        style={{
          backgroundColor: "indigo",
          width: "13px",
          height: "13px",
          borderRadius: "50%",
          right: "-6px",
        }}
      />

      <div className="bg-gray-50 rounded-lg p-3 space-y-3">
        {/* Attribute Dropdown/Combobox */}
        <div>
          <label className="block text-sm font-medium text-gray-700 mb-1">
            Select Attribute
          </label>
          <Combobox
            options={attributes.map((attr) => ({
              value: attr.name,
              label: attr.name,
            }))}
            value={selectedAttribute}
            onValueChange={handleAttributeChange}
            placeholder="Choose or create attribute"
            createOption
          />
        </div>

        {/* Predefined Value Input */}
        <div>
          <label className="block text-sm font-medium text-gray-700 mb-1">
            Attribute Value
          </label>
          <input
            type="text"
            value={predefinedValue}
            onChange={(e) => handlePredefinedValueChange(e.target.value)}
            className="w-full p-2 border rounded-md text-sm"
            placeholder="Attribute value"
          />
        </div>
      </div>
    </div>
  );
};

const nodeTypes = {
  triggerNode: TriggerNode,
  textButtonNode: TextButtonNode,
  mediaNode: MediaNode,
  listNode: ListNode,
  attributeNode: AttributeNode,
};

const edgeTypes = {
  custom: CustomEdge,
};

const FlowHeader = ({ flowName, flowId, generateFlowData }) => {
  const router = useRouter();
  const [isSaving, setIsSaving] = useState(false);
  const [isPublishing, setIsPublishing] = useState(false);

  const validateNodes = (nodes) => {
    const errors = [];

    nodes.forEach((node) => {
      switch (node.type) {
        case "textButtonNode":
          // Message body validation
          if (!node.data.content?.trim()) {
            errors.push(
              `Message ${node.data.messageNumber}: Message body is required`
            );
          }

          // Buttons validation
          if (!node.data.buttons || node.data.buttons.length === 0) {
            errors.push(
              `Message ${node.data.messageNumber}: At least one button is required`
            );
          } else {
            // Check each button has label (text)
            node.data.buttons.forEach((button, index) => {
              if (!button.label?.trim()) {
                // Changed from title to label
                errors.push(
                  `Message ${node.data.messageNumber}: Button ${
                    index + 1
                  } must have text`
                );
              }
              // Validate button text length
              if (button.label?.length > 20) {
                errors.push(
                  `Message ${node.data.messageNumber}: Button ${
                    index + 1
                  } text cannot exceed 20 characters`
                );
              }
            });
            // Validate maximum buttons
            if (node.data.buttons.length > 3) {
              errors.push(
                `Message ${node.data.messageNumber}: Cannot have more than 3 buttons`
              );
            }
          }
          break;

        case "mediaNode":
          // Message body validation
          if (!node.data.content?.trim()) {
            errors.push(
              `Message ${node.data.messageNumber}: Message body is required`
            );
          }

          // Media validation
          if (!node.data.mediaUrl) {
            errors.push(
              `Message ${node.data.messageNumber}: Media file is required`
            );
          }

          // Buttons validation
          if (!node.data.buttons || node.data.buttons.length === 0) {
            errors.push(
              `Message ${node.data.messageNumber}: At least one button is required`
            );
          } else {
            // Check each button has label (text)
            node.data.buttons.forEach((button, index) => {
              if (!button.label?.trim()) {
                // Changed from title to label
                errors.push(
                  `Message ${node.data.messageNumber}: Button ${
                    index + 1
                  } must have text`
                );
              }
              // Validate button text length
              if (button.label?.length > 20) {
                errors.push(
                  `Message ${node.data.messageNumber}: Button ${
                    index + 1
                  } text cannot exceed 20 characters`
                );
              }
            });
            // Validate maximum buttons
            if (node.data.buttons.length > 3) {
              errors.push(
                `Message ${node.data.messageNumber}: Cannot have more than 3 buttons`
              );
            }
          }
          break;

        case "listNode":
          // Message body validation
          if (!node.data.content?.trim()) {
            errors.push(
              `Message ${node.data.messageNumber}: Message body is required`
            );
          }

          // List button text validation
          if (!node.data.buttonText?.trim()) {
            errors.push(
              `Message ${node.data.messageNumber}: List button text is required`
            );
          }
          // Validate button text length
          if (node.data.buttonText?.length > 20) {
            errors.push(
              `Message ${node.data.messageNumber}: List button text cannot exceed 20 characters`
            );
          }

          // Sections validation
          if (!node.data.sections || node.data.sections.length === 0) {
            errors.push(
              `Message ${node.data.messageNumber}: At least one section is required`
            );
          } else {
            // Validate each section
            node.data.sections.forEach((section, sectionIndex) => {
              // Section title validation
              if (!section.title?.trim()) {
                errors.push(
                  `Message ${node.data.messageNumber}: Section ${
                    sectionIndex + 1
                  } must have a title`
                );
              }
              // Validate section title length
              if (section.title?.length > 24) {
                errors.push(
                  `Message ${node.data.messageNumber}: Section ${
                    sectionIndex + 1
                  } title cannot exceed 24 characters`
                );
              }

              // Rows validation
              if (!section.rows || section.rows.length === 0) {
                errors.push(
                  `Message ${node.data.messageNumber}: Section ${
                    sectionIndex + 1
                  } must have at least one row`
                );
              } else {
                // Validate each row
                section.rows.forEach((row, rowIndex) => {
                  if (!row.title?.trim()) {
                    errors.push(
                      `Message ${node.data.messageNumber}: Row ${
                        rowIndex + 1
                      } in Section ${sectionIndex + 1} must have a title`
                    );
                  }
                  // Validate row title length
                  if (row.title?.length > 24) {
                    errors.push(
                      `Message ${node.data.messageNumber}: Row ${
                        rowIndex + 1
                      } in Section ${
                        sectionIndex + 1
                      } title cannot exceed 24 characters`
                    );
                  }
                  // Validate row description length if present
                  if (row.description && row.description.length > 72) {
                    errors.push(
                      `Message ${node.data.messageNumber}: Row ${
                        rowIndex + 1
                      } in Section ${
                        sectionIndex + 1
                      } description cannot exceed 72 characters`
                    );
                  }
                });
              }
            });

            // Validate section count
            if (node.data.sections.length > 10) {
              errors.push(
                `Message ${node.data.messageNumber}: Cannot have more than 10 sections`
              );
            }

            // Validate total row count across all sections
            const totalRows = node.data.sections.reduce(
              (total, section) => total + (section.rows?.length || 0),
              0
            );
            if (totalRows > 10) {
              errors.push(
                `Message ${node.data.messageNumber}: Total number of rows cannot exceed 10`
              );
            }
          }
          break;

        case "attributeNode":
          if (!node.data.attribute1?.trim()) {
            errors.push(`Attribute Node: Select Attribute is required`);
          }
          if (!node.data.attribute2?.trim()) {
            errors.push(`Attribute Node: Attribute Value is required`);
          }
          break;
      }
    });

    return errors;
  };

  const handlePublish = async () => {
    setIsSaving(true);
    try {
      setIsPublishing(true);

      // Call the function to get flow data
      const flowData = generateFlowData();

      console.log(flowData, "this is result");

      if (!flowData || !flowData.nodes || !flowData.edges) {
        toast.error("Invalid flow data");
        return;
      }

      // Basic validation
      if (!flowData.nodes.length) {
        toast.error("Flow must contain at least one node");
        return;
      }

      if (!flowData.edges.length) {
        toast.error("Flow must contain at least one connection");
        return;
      }

      // Validate nodes
      const validationErrors = validateNodes(flowData.nodes);
      if (validationErrors.length > 0) {
        // Show all errors in a list using toast

        toast(
          (t) => (
            <div>
              <h3 className="font-semibold mb-2">
                Please fix the following errors:
              </h3>
              <ul className="list-disc pl-4">
                {validationErrors.map((error, index) => (
                  <li key={index} className="text-sm">
                    {error}
                  </li>
                ))}
              </ul>
            </div>
          ),
          {
            duration: 4000, // Longer duration to read all errors
            style: {
              maxWidth: "500px",
              padding: "16px",
            },
          }
        );
        return;
      }

      const response = await axios.post(
        `${process.env.NEXT_PUBLIC_BASE_URL}/automation/${flowId}/save/`,
        {
          flowData: flowData,
        }
      );

      toast.success("Flow published successfully");
      setIsSaving(false);
    } catch (error) {
      setIsSaving(false);
      console.error("Error publishing flow:", error);
      toast.error("Failed to publish flow");
    } finally {
      setIsSaving(false);
      setIsPublishing(false);
    }
  };

  return (
    <div className="bg-white border-b border-gray-200">
      <div className="px-4 sm:px-6 lg:px-8 py-4">
        <div className="flex items-center justify-between">
          {/* Left side - Back arrow, Flow name and save status */}
          <div className="flex items-center space-x-4">
            <button
              onClick={() => router.push("/automations/whatsapp")}
              className="p-1 rounded-full hover:bg-gray-100 transition-colors duration-200"
              title="Go back"
            >
              <svg
                className="w-6 h-6 text-gray-600"
                fill="none"
                stroke="currentColor"
                viewBox="0 0 24 24"
              >
                <path
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  strokeWidth={2}
                  d="M10 19l-7-7m0 0l7-7m-7 7h18"
                />
              </svg>
            </button>
            <div className="flex items-center space-x-4">
              <h1 className="text-xl font-semibold text-gray-900 flex items-center">
                {flowName}
              </h1>
              <span className="text-sm bg-gray-50 px-3 py-1 rounded-full border border-gray-200 text-gray-600 flex items-center">
                {isSaving ? (
                  <div className="flex items-center">
                    <svg
                      className="animate-spin h-4 w-4 mr-1.5 text-indigo-600"
                      viewBox="0 0 24 24"
                    >
                      <circle
                        className="opacity-25"
                        cx="12"
                        cy="12"
                        r="10"
                        stroke="currentColor"
                        strokeWidth="4"
                        fill="none"
                      />
                      <path
                        className="opacity-75"
                        fill="currentColor"
                        d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
                      />
                    </svg>
                    Saving changes...
                  </div>
                ) : (
                  <div className="flex items-center">
                    <svg
                      className="h-4 w-4 mr-1.5 text-green-500"
                      fill="none"
                      strokeLinecap="round"
                      strokeLinejoin="round"
                      strokeWidth="2"
                      viewBox="0 0 24 24"
                      stroke="currentColor"
                    >
                      <path d="M5 13l4 4L19 7" />
                    </svg>
                    All changes saved
                  </div>
                )}
              </span>
            </div>
          </div>

          {/* Right side - Actions */}
          <div className="flex items-center space-x-4">
            {/* Test Button */}
            <button
              onClick={() => {}} // Add your test logic here
              className="inline-flex items-center px-4 py-2 border border-indigo-600 rounded-md text-sm font-medium text-indigo-700 bg-white hover:bg-indigo-50 hover:border-indigo-700 transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 shadow-sm"
            >
              <svg
                xmlns="http://www.w3.org/2000/svg"
                className="h-4 w-4 mr-2"
                fill="none"
                viewBox="0 0 24 24"
                stroke="currentColor"
              >
                <path
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  strokeWidth={2}
                  d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"
                />
                <path
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  strokeWidth={2}
                  d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
                />
              </svg>
              Test Flow
            </button>

            {/* Publish Button */}
            <button
              onClick={handlePublish}
              className={`inline-flex items-center px-4 py-2 border border-transparent rounded-md text-sm font-medium text-white shadow-sm transition-colors duration-200 ${
                isPublishing
                  ? "bg-indigo-500 cursor-not-allowed"
                  : "bg-indigo-600 hover:bg-indigo-700"
              } focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500`}
              disabled={isPublishing}
            >
              {isPublishing ? (
                <>
                  <svg
                    className="animate-spin -ml-1 mr-2 h-4 w-4 text-white"
                    xmlns="http://www.w3.org/2000/svg"
                    fill="none"
                    viewBox="0 0 24 24"
                  >
                    <circle
                      className="opacity-25"
                      cx="12"
                      cy="12"
                      r="10"
                      stroke="currentColor"
                      strokeWidth="4"
                    ></circle>
                    <path
                      className="opacity-75"
                      fill="currentColor"
                      d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
                    ></path>
                  </svg>
                  Publishing...
                </>
              ) : (
                <>
                  <svg
                    className="h-4 w-4 mr-2"
                    fill="none"
                    stroke="currentColor"
                    viewBox="0 0 24 24"
                  >
                    <path
                      strokeLinecap="round"
                      strokeLinejoin="round"
                      strokeWidth={2}
                      d="M5 13l4 4L19 7"
                    />
                  </svg>
                  Publish Flow
                </>
              )}
            </button>
          </div>
        </div>
      </div>
    </div>
  );
};

// In your Flow component
const Flow = ({ setGenerateFlowData, initialFlowData, flowId }) => {
  // Add event handlers to the initial nodes

  const onEdgeDelete = useCallback((edgeId) => {
    setEdges((eds) => eds.filter((edge) => edge.id !== edgeId));
  }, []);

  // Initialize nodes
  const defaultTriggerNode = {
    id: "1",
    type: "triggerNode",
    position: { x: 400, y: 200 },
    data: {
      keywords: ["Hi"],
      onKeywordsUpdate: handleKeywordsUpdate,
    },
  };

  const [nodes, setNodes, onNodesChange] = useNodesState(
    initialFlowData?.nodes && initialFlowData.nodes.length > 0
      ? initialFlowData.nodes
      : [defaultTriggerNode]
  );

  // Initialize edges with the ref function
  const [edges, setEdges, onEdgesChange] = useEdgesState(
    initialFlowData?.edges?.map((edge) => ({
      id: edge.sourceHandle
        ? `edge-${edge.source}-${edge.sourceHandle}-${edge.target}`
        : `edge-${edge.source}-${edge.target}`,
      source: edge.source,
      sourceHandle: edge.sourceHandle,
      target: edge.target,
      type: "custom",
      data: {
        sourceButtonText: edge.data?.sourceButtonText,
        onDelete: onEdgeDelete,
      },
    })) || []
  );

  const [isDropdownVisible, setDropdownVisible] = useState(false);
  const [dropdownPosition, setDropdownPosition] = useState({ x: 0, y: 0 });
  const [pendingConnection, setPendingConnection] = useState(null);
  const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });

  useEffect(() => {
    if (initialFlowData?.nodes) {
      setNodes((nodes) =>
        nodes.map((node) => ({
          ...node,
          data: {
            ...node.data,
            onKeywordsUpdate: handleKeywordsUpdate, // Add this line
            onButtonUpdate: handleButtonsUpdate,
            onContentUpdate: handleContentUpdate,
            onButtonsUpdate: handleButtonsUpdate,
            onMediaUpdate: handleMediaUpdate,
            onItemsUpdate: handleItemsUpdate,
            onAttributeUpdate: handleAttributeUpdate,
            onButtonTextUpdate: handleButtonTextUpdate,
            onSectionsUpdate: handleSectionsUpdate,
            onDelete: () => handleNodeDelete(node.id),
          },
        }))
      );
    }
  }, [initialFlowData]);

  // Handle node deletion
  const onNodesDelete = useCallback(
    (deleted) => {
      // Filter out the trigger node from deletion
      const nodesToDelete = deleted.filter(
        (node) => node.type !== "triggerNode"
      );

      // Remove associated edges
      const edgesToDelete = edges.filter((edge) =>
        nodesToDelete.find(
          (node) => node.id === edge.source || node.id === edge.target
        )
      );

      setEdges((eds) =>
        eds.filter((edge) => !edgesToDelete.find((del) => del.id === edge.id))
      );
    },
    [edges, setEdges]
  );

  function handleButtonsUpdate(nodeId, newButtons) {
    setNodes((nds) =>
      nds.map((node) => {
        if (node.id === nodeId) {
          return {
            ...node,
            data: {
              ...node.data,
              buttons: newButtons,
            },
          };
        }
        return node;
      })
    );
  }

  function handleContentUpdate(nodeId, newContent) {
    setNodes((nds) =>
      nds.map((node) => {
        if (node.id === nodeId) {
          return {
            ...node,
            data: {
              ...node.data,
              content: newContent,
            },
          };
        }
        return node;
      })
    );
  }

  function handleMediaUpdate(
    nodeId,
    mediaUrl,
    mediaType,
    uploadedId,
    fileName
  ) {
    setNodes((nds) =>
      nds.map((node) => {
        if (node.id === nodeId) {
          return {
            ...node,
            data: {
              ...node.data,
              mediaUrl,
              mediaType,
              uploadedId: uploadedId, // Make sure this is set
              fileName: fileName, // Make sure this is set
            },
          };
        }
        return node;
      })
    );
  }

  function handleItemsUpdate(nodeId, newItems) {
    setNodes((nds) =>
      nds.map((node) => {
        if (node.id === nodeId) {
          return {
            ...node,
            data: {
              ...node.data,
              items: newItems,
            },
          };
        }
        return node;
      })
    );
  }

  function handleAttributeUpdate(nodeId, field, value) {
    setNodes((nds) =>
      nds.map((node) => {
        if (node.id === nodeId) {
          return {
            ...node,
            data: {
              ...node.data,
              [field]: value,
            },
          };
        }
        return node;
      })
    );
  }

  function handleKeywordsUpdate(nodeId, newKeywords) {
    setNodes((nds) =>
      nds.map((node) => {
        if (node.id === nodeId) {
          return {
            ...node,
            data: {
              ...node.data,
              keywords: newKeywords,
              onKeywordsUpdate: handleKeywordsUpdate,
            },
          };
        }
        return node;
      })
    );
  }

  function handleButtonTextUpdate(nodeId, newButtonText) {
    setNodes((nds) =>
      nds.map((node) => {
        if (node.id === nodeId) {
          return {
            ...node,
            data: {
              ...node.data,
              buttonText: newButtonText,
            },
          };
        }
        return node;
      })
    );
  }

  function handleSectionsUpdate(nodeId, newSections) {
    setNodes((nds) =>
      nds.map((node) => {
        if (node.id === nodeId) {
          return {
            ...node,
            data: {
              ...node.data,
              sections: newSections,
            },
          };
        }
        return node;
      })
    );
  }

  const onConnectStart = useCallback((_, { nodeId, handleId }) => {
    setPendingConnection({ sourceId: nodeId, sourceHandleId: handleId });
    setDropdownVisible(false);
  }, []);

  const onConnectEnd = useCallback((event) => {
    const targetNode = event.target.closest(".react-flow__node");

    if (!targetNode) {
      const bounds = document
        .querySelector(".react-flow")
        .getBoundingClientRect();

      // Calculate position relative to the viewport
      const position = {
        x: event.clientX - bounds.left,
        y: event.clientY - bounds.top,
      };

      setDropdownPosition(position);
      setMousePosition(position);
      setDropdownVisible(true);
    }
  }, []);

  /// Modify the onConnect function to ensure onDelete is passed
  const onConnect = useCallback(
    (params) => {
      const sourceNode = nodes.find((node) => node.id === params.source);
      const sourceButtonText = sourceNode?.data?.buttons?.find(
        (btn) => btn.handleId === params.sourceHandle
      )?.label;

      const newEdge = {
        ...params,
        id: params.sourceHandle
          ? `edge-${params.source}-${params.sourceHandle}-${params.target}`
          : `edge-${params.source}-${params.target}`,
        type: "custom",
        data: {
          onDelete: onEdgeDelete,
          sourceButtonText: sourceButtonText,
        },
      };

      setEdges((eds) => addEdge(newEdge, eds));
    },
    [nodes, onEdgeDelete]
  );
  const isConnectionAllowed = useCallback(() => {
    return true; // Allow all connections
  }, []);

  // Add this state to track the flow viewport
  const [viewport, setViewport] = useState({ x: 0, y: 0, zoom: 1 });

  // Update viewport state when it changes
  const onViewportChange = useCallback((viewport) => {
    setViewport(viewport);
  }, []);

  const handleDropdownSelect = useCallback(
    (option) => {
      if (!pendingConnection) return;

      const newNodeId = `node-${Date.now()}`;
      const messageNodes = nodes.filter((node) =>
        ["textButtonNode", "mediaNode", "listNode"].includes(node.type)
      );
      const messageNumber = messageNodes.length + 1;

      // Calculate the actual position considering viewport transform
      const position = {
        x: (dropdownPosition.x - viewport.x) / viewport.zoom,
        y: (dropdownPosition.y - viewport.y) / viewport.zoom,
      };

      let nodeType;
      switch (option) {
        case "Text + Button":
          nodeType = "textButtonNode";
          break;
        case "Media":
          nodeType = "mediaNode";
          break;
        case "List":
          nodeType = "listNode";
          break;
        case "Attribute":
          nodeType = "attributeNode";
          break;
        default:
          nodeType = "textButtonNode";
      }

      // Create new node with corrected position
      const newNode = {
        id: newNodeId,
        type: nodeType,
        position: position, // Use the corrected position
        data: {
          type: option,
          content: "",
          buttons: [],
          messageNumber: nodeType !== "attributeNode" ? messageNumber : null,
          onButtonUpdate: handleButtonsUpdate,
          onContentUpdate: handleContentUpdate,
          onButtonsUpdate: handleButtonsUpdate,
          onMediaUpdate: handleMediaUpdate,
          onItemsUpdate: handleItemsUpdate,
          onAttributeUpdate: handleAttributeUpdate,
          onButtonTextUpdate: handleButtonTextUpdate,
          onSectionsUpdate: handleSectionsUpdate,
          onDelete: () => handleNodeDelete(newNodeId),
        },
      };

      // Create new edge if there's a pending connection
      if (pendingConnection.sourceId) {
        const newEdge = {
          id: pendingConnection.sourceHandleId
            ? `edge-${pendingConnection.sourceId}-${pendingConnection.sourceHandleId}-${newNodeId}`
            : `edge-${pendingConnection.sourceId}-${newNodeId}`,
          source: pendingConnection.sourceId,
          sourceHandle: pendingConnection.sourceHandleId,
          target: newNodeId,
          type: "custom",
          data: {
            onDelete: onEdgeDelete,
          },
        };

        setEdges((eds) => [...eds, newEdge]);
      }

      setNodes((nds) => [...nds, newNode]);
      setDropdownVisible(false);
      setPendingConnection(null);
    },
    [pendingConnection, dropdownPosition, viewport, nodes, setNodes, setEdges]
  );

  // Handle node deletion
  const handleNodeDelete = useCallback(
    (nodeId) => {
      setNodes((nds) => {
        const filteredNodes = nds.filter((node) => node.id !== nodeId);
        // Recalculate message numbers
        return filteredNodes.map((node) => {
          if (["textButtonNode", "mediaNode", "listNode"].includes(node.type)) {
            const newMessageNumber =
              filteredNodes.filter(
                (n) =>
                  ["textButtonNode", "mediaNode", "listNode"].includes(
                    n.type
                  ) && n.id < node.id
              ).length + 1;
            return {
              ...node,
              data: {
                ...node.data,
                messageNumber: newMessageNumber,
              },
            };
          }
          return node;
        });
      });

      setEdges((eds) =>
        eds.filter((edge) => edge.source !== nodeId && edge.target !== nodeId)
      );
    },
    [setNodes, setEdges]
  );

  const generateFlowData = useCallback(() => {
    const mappedNodes = nodes.map((node) => {
      const baseNodeData = {
        id: node.id,
        type: node.type,
        position: node.position,
      };

      switch (node.type) {
        case "triggerNode":
          return {
            ...baseNodeData,
            data: {
              keywords: node.data.keywords || [],
            },
          };

        case "textButtonNode":
          return {
            ...baseNodeData,
            data: {
              content: node.data.content || "",
              buttons:
                node.data.buttons?.map((button) => ({
                  label: button.label,
                  handleId: button.handleId,
                })) || [],
              messageNumber: node.data.messageNumber,
            },
          };

        case "mediaNode":
          return {
            ...baseNodeData,
            data: {
              content: node.data.content || "",
              mediaUrl: node.data.mediaUrl || "",
              mediaType: node.data.mediaType || "",
              uploadedId: node.data.uploadedId || "",
              fileName: node.data.fileName || "",
              buttons:
                node.data.buttons?.map((button) => ({
                  label: button.label,
                  handleId: button.handleId,
                })) || [],
              messageNumber: node.data.messageNumber,
            },
          };

        case "listNode":
          return {
            ...baseNodeData,
            data: {
              content: node.data.content || "",
              buttonText: node.data.buttonText || "Options",
              sections:
                node.data.sections?.map((section) => ({
                  title: section.title,
                  rows: section.rows.map((row) => ({
                    id: row.id,
                    title: row.title,
                    description: row.description,
                  })),
                })) || [],
              messageNumber: node.data.messageNumber,
            },
          };

        case "attributeNode":
          return {
            ...baseNodeData,
            data: {
              attribute1: node.data.attribute1 || "",
              attribute2: node.data.attribute2 || "",
            },
          };

        default:
          return baseNodeData;
      }
    });

    // Modify how edges are mapped to include all necessary data
    const mappedEdges = edges.map((edge) => ({
      id: edge.sourceHandle
        ? `edge-${edge.source}-${edge.sourceHandle}-${edge.target}`
        : `edge-${edge.source}-${edge.target}`,
      source: edge.source,
      sourceHandle: edge.sourceHandle,
      target: edge.target,
      type: edge.type,
      data: {
        sourceButtonText: edge.data?.sourceButtonText,
      },
    }));

    return {
      nodes: mappedNodes,
      edges: mappedEdges,
    };
  }, [nodes, edges]);

  // Update the parent component with the generation function
  useEffect(() => {
    setGenerateFlowData(() => generateFlowData);
  }, [generateFlowData, setGenerateFlowData]);

  const [reactFlowInstance, setReactFlowInstance] = useState(null);

  // Function to handle quick navigation
  const handleQuickNav = (direction) => {
    if (!reactFlowInstance) return;

    const nodes = reactFlowInstance.getNodes();
    if (!nodes.length) return;

    // Calculate bounds
    let targetY;
    if (direction === "top") {
      targetY = Math.min(...nodes.map((node) => node.position.y)) - 100;
    } else {
      targetY = Math.max(...nodes.map((node) => node.position.y)) + 100;
    }

    // Smooth scroll to position
    reactFlowInstance.setViewport(
      {
        x: reactFlowInstance.getViewport().x,
        y: -targetY,
        zoom: reactFlowInstance.getViewport().zoom,
      },
      { duration: 800 }
    );
  };

  // Add new state for tracking save status
  const [lastSaved, setLastSaved] = useState(null);
  const [saveStatus, setSaveStatus] = useState("All changes saved");

  // Function to format current date-time in UTC
  const formatDateTime = () => {
    const now = new Date();
    return now.toLocaleTimeString("en-IN", {
      hour: "2-digit",
      minute: "2-digit",
      second: "2-digit",
      hour12: true,
    });
  };
  // Function to save flow data
  const saveFlowData = useCallback(async () => {
    try {
      const flowData = generateFlowData();

      const response = await axios.post(
        `${process.env.NEXT_PUBLIC_BASE_URL}/automation/${flowId}/save/`,
        {
          flowData: flowData,
        }
      );

      if (response.status !== 200) {
        throw new Error("Failed to save");
      }

      setLastSaved(formatDateTime());
      setSaveStatus("All changes saved");

      console.log("all change saved");

      // Optional: Show success toast
      // toast.success('Flow autosaved successfully');
    } catch (error) {
      console.error("Autosave failed:", error);
      setSaveStatus("Failed to save");
      toast.error("Failed to autosave flow");
    }
  }, [generateFlowData, flowId]);

  // Set up autosave interval
  useEffect(() => {
    if (!flowId) return; // Don't set up autosave if no flowId

    // Save every 5 minutes
    const autoSaveInterval = setInterval(() => {
      setSaveStatus("Saving...");
      saveFlowData();
    }, 5 * 60 * 1000); // 5 minutes

    // Save when user leaves the page
    // const handleBeforeUnload = (e) => {
    //   saveFlowData();
    //   e.preventDefault();
    //   e.returnValue =
    //     "You have unsaved changes. Are you sure you want to leave?";
    // };

    // window.addEventListener("beforeunload", handleBeforeUnload);

    // Cleanup
    return () => {
      clearInterval(autoSaveInterval);
      // window.removeEventListener("beforeunload", handleBeforeUnload);
    };
  }, [saveFlowData, flowId]);

  return (
    <div className="relative w-full h-[calc(100vh-64px)] overflow-hidden">
      <ReactFlow
        nodes={nodes}
        edges={edges}
        onNodesChange={onNodesChange}
        onEdgesChange={onEdgesChange}
        onConnectStart={onConnectStart}
        onConnectEnd={onConnectEnd}
        onConnect={onConnect}
        nodeTypes={nodeTypes}
        edgeTypes={edgeTypes}
        defaultEdgeOptions={{
          type: "custom",
          data: { onDelete: onEdgeDelete },
        }}
        connectionMode="loose"
        fitView
        onInit={setReactFlowInstance}
        onViewportChange={onViewportChange}
      >
        <Controls
          position="bottom-left"
          style={{ position: "fixed", left: 20, bottom: 20 }}
          showInteractive={false}
        />
        <MiniMap
          position="bottom-right"
          style={{ position: "fixed", right: 20, bottom: 100 }}
          zoomable
          pannable
        />
        <Background gap={12} size={1} />
      </ReactFlow>

      <div className="absolute right-8 top-4 flex items-center gap-2 bg-white px-4 py-2 rounded-md shadow-sm border border-gray-200 z-[1000]">
        <div className="flex items-center gap-2">
          {saveStatus === "Saving..." ? (
            <svg
              className="animate-spin h-4 w-4 text-gray-500"
              xmlns="http://www.w3.org/2000/svg"
              fill="none"
              viewBox="0 0 24 24"
            >
              <circle
                className="opacity-25"
                cx="12"
                cy="12"
                r="10"
                stroke="currentColor"
                strokeWidth="4"
              ></circle>
              <path
                className="opacity-75"
                fill="currentColor"
                d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
              ></path>
            </svg>
          ) : saveStatus === "Failed to save" ? (
            <svg
              className="h-4 w-4 text-red-500"
              fill="none"
              stroke="currentColor"
              viewBox="0 0 24 24"
            >
              <path
                strokeLinecap="round"
                strokeLinejoin="round"
                strokeWidth="2"
                d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
              ></path>
            </svg>
          ) : (
            <svg
              className="h-4 w-4 text-green-500"
              fill="none"
              stroke="currentColor"
              viewBox="0 0 24 24"
            >
              <path
                strokeLinecap="round"
                strokeLinejoin="round"
                strokeWidth="2"
                d="M5 13l4 4L19 7"
              ></path>
            </svg>
          )}
          <span className="text-sm text-gray-600">{saveStatus}</span>
        </div>
        {lastSaved && (
          <span className="text-xs text-gray-400">Last saved: {lastSaved}</span>
        )}
      </div>

      {/* Quick Navigation Controls */}
      {/* <div className="absolute right-8 top-1/2 transform -translate-y-1/2 flex flex-col gap-4 z-[1000]">
        <button
          onClick={() => handleQuickNav("top")}
          className="p-3 bg-white rounded-full shadow-lg hover:bg-gray-50 transition-colors duration-200 group"
          title="Scroll to top"
        >
          <svg
            className="w-5 h-5 text-gray-600 group-hover:text-indigo-600"
            fill="none"
            viewBox="0 0 24 24"
            stroke="currentColor"
          >
            <path
              strokeLinecap="round"
              strokeLinejoin="round"
              strokeWidth={2}
              d="M5 15l7-7 7 7"
            />
          </svg>
        </button>

        <button
          onClick={() => handleQuickNav("bottom")}
          className="p-3 bg-white rounded-full shadow-lg hover:bg-gray-50 transition-colors duration-200 group"
          title="Scroll to bottom"
        >
          <svg
            className="w-5 h-5 text-gray-600 group-hover:text-indigo-600"
            fill="none"
            viewBox="0 0 24 24"
            stroke="currentColor"
          >
            <path
              strokeLinecap="round"
              strokeLinejoin="round"
              strokeWidth={2}
              d="M19 9l-7 7-7-7"
            />
          </svg>
        </button>
      </div> */}

      {isDropdownVisible && (
        <div className="z-[1000]">
          <NodeTypeDropdown
            options={["Text + Button", "Media", "List", "Attribute"]}
            onSelect={handleDropdownSelect}
            onCancel={() => {
              setDropdownVisible(false);
              setPendingConnection(null);
            }}
            position={dropdownPosition}
          />
        </div>
      )}
    </div>
  );
};

// Add this function to handle publishing

export default function WhatsAppFlow() {
  const router = useRouter();
  const { flowId } = router.query;
  const [flowName, setFlowName] = useState("");
  const [generateFlowData, setGenerateFlowData] = useState(() => () => ({}));
  const [initialFlowData, setInitialFlowData] = useState(null);

  useEffect(() => {
    if (flowId) {
      const fetchFlowDetails = async () => {
        try {
          const response = await axios.get(
            `${process.env.NEXT_PUBLIC_BASE_URL}/automation/${flowId}/`
          );
          setFlowName(response.data.name);
          // If there's no flowData or it's empty, create default structure
          const flowData = response.data.flowData || {
            nodes: [],
            edges: [],
          };
          setInitialFlowData(flowData);
          console.log(response.data.flowData, "!!!!!!!!!!");
        } catch (error) {
          // If it fails to fetch (new flow), initialize with empty data
          setInitialFlowData({
            nodes: [],
            edges: [],
          });
          toast.error("Failed to load flow details");
          console.error("Error fetching flow details:", error);
        }
      };

      fetchFlowDetails();
    }
  }, [flowId]);

  if (!flowId || !initialFlowData) return null;

  return (
    <Layout>
      <FlowHeader
        flowName={flowName}
        flowId={flowId}
        generateFlowData={generateFlowData}
      />
      <ReactFlowProvider>
        <Flow
          setGenerateFlowData={setGenerateFlowData}
          initialFlowData={initialFlowData}
          flowId={flowId}
        />
      </ReactFlowProvider>
      <Toaster position="top-center" />
    </Layout>
  );
}

Comments

Popular posts from this blog

REACT NATIVE STYLE TRICKS

Tips for Django

chat model