import { useState, useCallback, useEffect } from 'react';
import {
  ReactFlow,
  addEdge,
  Controls,
  Background,
  BackgroundVariant,
  MarkerType,
  useReactFlow,
  ReactFlowProvider,
  useNodesState,
  useEdgesState,
  useStoreApi,
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';
import '../assets/css/style.css';
import Tabbar from './Tabbar.tsx';
import ShowPopup from './ShowPopup.tsx';
import { nanoid } from 'nanoid';
import CustomEdge from './CustomEdge';
import MenuFlow from './MenuFlow';
import DeleteNodeModal from './popup/DeleteNodeModal.tsx';

// Nội dung cho mỗi node
const nodeContents = {
  'send-email': `
    <label for="email-subject">Subject:</label>
    <input type="text" id="email-subject" name="email-subject" placeholder="Enter subject">
    <label for="email-body">Body:</label>
    <textarea id="email-body" name="email-body" rows="4" placeholder="Enter email body"></textarea>
  `,
  'customer-sign': `
    <label for="customer-name">Customer Name:</label>
    <input type="text" id="customer-name" name="customer-name" placeholder="Enter customer name">
    <label for="customer-email">Customer Email:</label>
    <input type="email" id="customer-email" name="customer-email" placeholder="Enter customer email">
  `,
  ifelse: `
    <label for="reply-status">Reply Status:</label>
    <select id="reply-status" name="reply-status">
      <option value="replied">Replied</option>
      <option value="not-replied">Not Replied</option>
    </select>
  `,
  'contact-exists': `
    <label for="contact-id">Contact ID:</label>
    <input type="text" id="contact-id" name="contact-id" placeholder="Enter contact ID">
  `,
  'send-survey': `
    <label for="survey-question">Survey Question:</label>
    <input type="text" id="survey-question" name="survey-question" placeholder="Enter survey question">
    <label for="survey-options">Options (comma-separated):</label>
    <input type="text" id="survey-options" name="survey-options" placeholder="Option 1, Option 2, ...">
  `,
};

const NodeFlow = ({ initialNodes, initialEdges }) => {
  const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
  const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
  const [showTabBar, setShowTabBar] = useState(false);
  const [lastNodeId, setLastNodeId] = useState(nodes[0].id);
  const [showPopup, setShowPopup] = useState(false);
  const [selectedNodeContent, setSelectedNodeContent] = useState('');
  const [addNodeCallback, setAddNodeCallback] = useState(() => () => {});
  const [isTabbarVisible, setIsTabbarVisible] = useState(false);
  const { screenToFlowPosition } = useReactFlow();
  const [showActions, setShowActions] = useState(null);
  const [showPopupSuccess, setShowPopupSuccess] = useState(false);
  const store = useStoreApi();
  const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
  const [deleteNodeId, setDeleteNodeId] = useState(null);

  const handleAddNoteClick = () => {
    setShowTabBar(true);
    setIsTabbarVisible(true);
    setAddNodeCallback(() => (selectedNode) => {
      addNodeBetween(selectedNode, sourceId, targetId);
    });
  };
  const closeTabbar = () => {
    setIsTabbarVisible(false); // Ẩn tabbar khi click close
  };

  const onNodeClick = (event, node) => {
    if (node.key === 'add-node') {
      // Check if the clicked node is "Add Node"
      setShowTabBar(true);
      setIsTabbarVisible(true);
    }
  };

  const getNextYPosition = (xPosition, spacing) => {
    const nodesInColumn = nodes.filter((node) => node.position.x === xPosition);
    if (nodesInColumn.length === 0) return 0; // Return 0 if there are no nodes

    const lastNode = nodesInColumn[nodesInColumn.length - 1];
    return lastNode.position.y + spacing;
  };

  const addNode = (option) => {
    const newNodeId = nanoid(8); // Generate a unique ID for the new node
    const addNoteNode = nodes.find((node) => node.key === 'add-node');
    const initialX = addNoteNode?.position.x;

    const nextY =
      nodes.length > 2
        ? getNextYPosition(initialX, 120)
        : addNoteNode?.position.y;

    // Remove existing edges from addNoteNode
    setEdges((eds) =>
      eds.filter((edge) => edge.source !== '2' && edge.target !== '2')
    );

    if (option.id === '4') {
      const repliedNode = {
        id: newNodeId,
        key: option.key,
        data: { label: option.htmlNode },
        position: { x: initialX, y: nextY },
      };

      const yesNode = {
        id: nanoid(8),
        type: 'output',
        key: 'contact-exists',
        data: {
          label: (
            <div className="step">
              <div className="left">
                <img
                  src="/src/assets/icons/icon-check.svg"
                  width="24px"
                  height="24px"
                  alt=""
                />
              </div>
              <div className="right">Contact Exists</div>
            </div>
          ),
        },
        position: { x: initialX - 150, y: nextY + 150 },
      };

      const noNode = {
        id: nanoid(8),
        type: '',
        key: 'send-survey',
        data: {
          label: (
            <div className="step">
              <div className="left">
                <img
                  src="/src/assets/icons/icon-list.svg"
                  width="24px"
                  height="24px"
                  alt=""
                />
              </div>
              <div className="right">Send survey</div>
            </div>
          ),
        },
        position: { x: initialX + 150, y: nextY + 150 },
      };

      // Di chuyển node add-note sang nhánh no
      setNodes((nds) =>
        nds.map((node) =>
          node.id === '2'
            ? {
                ...node,
                position: {
                  x: noNode.position.x,
                  y: noNode.position.y + 150,
                },
              }
            : node
        )
      );

      // Thêm các node mới (replied, yes, no)
      setNodes((nds) => [...nds, repliedNode, yesNode, noNode]);

      // Kết nối các edges giữa các node
      setEdges((eds) => [
        ...eds,
        {
          id: nanoid(8),
          source: repliedNode.id,
          target: yesNode.id,
          label: 'yes',
        },
        {
          id: nanoid(8),
          source: repliedNode.id,
          target: noNode.id,
          label: 'no',
        },
        { id: nanoid(8), source: lastNodeId, target: repliedNode.id },
        { id: nanoid(8), source: noNode.id, target: addNoteNode.id },
      ]);

      setLastNodeId(noNode.id);
    } else {
      // Add new node logic
      if (addNoteNode) {
        const initialX = addNoteNode.position.x;
        setNodes((nds) =>
          nds.map((node) =>
            node.key === 'add-node'
              ? {
                  ...node,
                  position: {
                    x: initialX,
                    y: nextY + 130,
                  },
                }
              : node
          )
        );
      }
      const newNode = {
        id: newNodeId,
        key: option.key,
        data: { label: option.htmlNode },
        position: {
          x: initialX,
          y: nodes.length > 2 ? nextY : addNoteNode.position.y,
        },
      };

      const newEdge = {
        id: nanoid(8),
        source: lastNodeId,
        target: newNodeId,
        // data: {
        //   label: <div onClick={handleAddNoteClick}>+</div>,
        //   onClick: handleAddNoteClick
        // }
      };

      setNodes((nds) => [...nds, newNode]);
      setEdges((eds) => [
        ...eds,
        newEdge,
        { id: nanoid(8), source: newNodeId, target: addNoteNode.id },
      ]);

      // setEdges((eds) => [
      //   ...eds,
      //   {
      //     id: nanoid(8),
      //     source: lastNodeId,
      //     data: {
      //       label: <div onClick={handleAddNoteClick}>Add Note</div>, // Use HTML or React component
      //       onClick: handleAddNoteClick
      //     },
      //     target: newNodeId
      //   },
      //   { id: nanoid(8), source: newNodeId, target: addNoteNode.id }
      // ]);

      // Cuộn tới node mới thêm
      setLastNodeId(newNodeId);
    }

    setShowTabBar(false);
  };

  const hidePopup = () => {
    setShowPopup(false);
  };

  const addPopup = (node) => {
    const content = nodeContents[node.id]; // Lấy nội dung từ nodeContents dựa trên ID node
    setSelectedNodeContent(content); // Cập nhật nội dung được chọn
  };

  const onDrop = (event: React.DragEvent) => {
    event.preventDefault();

    const type = JSON.parse(
      event.dataTransfer.getData('application/reactflow')
    );
    const position = screenToFlowPosition({
      x: event.clientX,
      y: event.clientY,
    });

    const newNodeId = nanoid(8);
    const addNodeId = '2';
    const addNode = nodes.find((node) => node.id === addNodeId);
    const targetEdge = edges.find(
      (edge) => edge?.source === '2' || edge?.target === '2'
    );
    const targetNodeId =
      targetEdge?.source === '2' ? targetEdge?.target : targetEdge?.source;
    const targetNode = nodes.find((node) => node.id === targetNodeId);

    const newNodePosition = targetNode
      ? { x: targetNode.position.x, y: targetNode.position.y + 110 }
      : position;

    const createNewNode = (
      nodeId: string,
      nodePosition: any,
      nodeLabel: JSX.Element
    ) => ({
      id: nodeId,
      key: type.key,
      type: type.type || 'default',
      data: { label: nodeLabel },
      position: nodePosition,
    });

    const newNode = createNewNode(
      newNodeId,
      newNodePosition,
      <div className="custom-node">
        <div className="step">
          <div className="left">
            <img src={type.icon} width="24px" height="24px" alt="" />
          </div>
          <div className="right">{type.label}</div>
        </div>
        <div className="manageStep">
          <button className="btn-show" onClick={() => toggleActions(newNodeId)}>
            <img
              src="/src/assets/icons/icon-wink.svg"
              width="20px"
              height="20px"
              alt="wink"
            />
          </button>

          <div className={`actions actions-${newNodeId}`}>
            <button
              onClick={() => handleEditNode(newNodeId)}
              className="btn-edit"
            >
              Sửa
            </button>
            <button
              onClick={() => handleDeleteNode(newNodeId, type.key)}
              className="btn-remove"
            >
              Xóa
            </button>
          </div>
        </div>
      </div>
    );

    setEdges((eds) =>
      eds.filter((edge) => edge.source !== '2' && edge.target !== '2')
    );

    if (type.key === 'ifelse') {
      const yesNodeId = nanoid(8);
      const noNodeId = nanoid(8);

      const createBranchNode = (id: string, xOffset: number) => ({
        id,
        key: 'add-node',
        data: {
          label: (
            <div className="add-node">
              <i>+</i> <span>Add a journey point</span>
            </div>
          ),
        },
        position: {
          x: newNode.position.x + xOffset,
          y: newNode.position.y + 150,
        },
      });

      const yesNode = createBranchNode(yesNodeId, -200);
      const noNode = createBranchNode(noNodeId, 200);

      const ifelseEdges = [
        { id: nanoid(8), source: targetNodeId, target: newNodeId },
        {
          id: nanoid(8),
          source: newNodeId,
          target: yesNodeId,
          type: 'custom',
          data: { label: 'Yes' },
        },
        {
          id: nanoid(8),
          source: newNodeId,
          target: noNodeId,
          type: 'custom',
          data: { label: 'No' },
        },
      ];

      setNodes((nds) => [
        ...nds.filter((node) => node.id !== addNodeId),
        newNode,
        yesNode,
        noNode,
      ]);
      setEdges((eds) => [...eds, ...ifelseEdges]);
    } else {
      if (targetNode) {
        const updatedEdges = [
          { id: nanoid(8), source: targetNodeId, target: newNodeId },
          { id: nanoid(8), source: newNodeId, target: '2' },
        ];

        // Cập nhật nodes
        setNodes((nds) => {
          const updatedNodes = [...nds, newNode];

          if (addNode) {
            // Tính toán vị trí cho addNode nằm dưới newNode
            const addNodePosition = {
              x: newNode.position.x,
              y: newNode.position.y + 110, // Đặt add-node dưới newNode
            };

            // Cập nhật vị trí của addNode
            const addNodeUpdated = updatedNodes.map((node) =>
              node.id === addNodeId
                ? { ...node, position: addNodePosition }
                : node
            );

            // Đảm bảo rằng add-node nằm dưới newNode
            return addNodeUpdated.sort((a, b) => {
              if (a.id === newNodeId) return -1; // Đặt newNode lên trước
              if (b.id === newNodeId) return 1; // Đặt addNode xuống dưới
              return 0; // Giữ nguyên thứ tự cho các node khác
            });
          }

          return updatedNodes;
        });

        // Cập nhật edges
        setEdges((eds) => [...eds, ...updatedEdges]);

        if (addNode && type.key === 'contact-exists') {
          // Nếu key là 'contact-exists', xóa addNode
          setNodes((nds) => nds.filter((node) => node.id !== addNodeId));
        }
      } else {
        const newNodeNew = createNewNode(
          newNodeId,
          position,
          newNode.data.label
        );
        let closestNode = null;
        let closestDistance = Infinity;
        const threshold = 150;

        nodes.forEach((node) => {
          const distance = getDistance(newNodeNew.position, node.position);
          if (distance < closestDistance && distance <= threshold) {
            closestDistance = distance;
            closestNode = node;
          }
        });

        if (closestNode) {
          const updatedEdges = edges.map((edge) => {
            if (edge.source === closestNode.id)
              return { ...edge, source: newNodeNew.id };
            if (edge.target === closestNode.id)
              return { ...edge, target: newNodeNew.id };
            return edge;
          });

          if (newNodeNew.type !== 'output') {
            const addNodeNew = createNewNode(
              nanoid(8),
              { x: closestNode.position.x, y: closestNode.position.y + 100 },
              <div className="add-node">
                <i>+</i> <span>Add a journey point</span>
              </div>
            );

            setNodes((nds) => [
              ...nds.map((n) =>
                n.id === closestNode.id
                  ? { ...newNodeNew, position: closestNode.position }
                  : n
              ),
              addNodeNew,
            ]);
            setEdges([
              ...updatedEdges,
              { id: nanoid(8), source: newNodeNew.id, target: addNodeNew.id },
            ]);
          } else {
            setNodes((nds) => [
              ...nds.map((n) =>
                n.id === closestNode.id
                  ? { ...newNodeNew, position: closestNode.position }
                  : n
              ),
            ]);
            setEdges(updatedEdges);
          }
        } else {
          setNodes((nds) => [...nds, newNodeNew]);
        }
      }
    }
  };

  const onDragOver = useCallback((event) => {
    event.preventDefault();
    event.dataTransfer.dropEffect = 'move';
  }, []);

  const defaultEdgeOptions = {
    style: { strokeWidth: 1.5, stroke: 'black' },
    type: 'floating',
    markerEnd: {
      type: MarkerType.ArrowClosed,
      color: 'black',
    },
  };

  const onConnect = useCallback(
    (params) => setEdges((eds) => addEdge(params, eds)),
    [setEdges]
  );

  // Hàm tính khoảng cách giữa hai node
  const getDistance = (pos1, pos2) => {
    const dx = pos1.x - pos2.x;
    const dy = pos1.y - pos2.y;
    return Math.sqrt(dx * dx + dy * dy);
  };

  const toggleActions = (nodeId: string) => {
    setShowActions((prev) => (prev === nodeId ? null : nodeId));
    const actionsElement = document.querySelector(`.actions-${nodeId}`);
    if (actionsElement) {
      // Toggle class 'show' cho phần tử actions
      actionsElement.classList.toggle('staticNode');
    }
  };

  // Hàm xóa node
  const handleDeleteNode = useCallback(
    (nodeId, nodeKey) => {
      // Tìm tất cả các edges có nodeId là source hoặc target
      const allNode = store.getState();
      const edgeNode = allNode.edges;
      const Node = allNode.nodes;

      if (nodeKey === 'ifelse') {
        setDeleteNodeId(nodeId); // Lưu lại ID của node muốn xóa
        // Hiển thị modal để người dùng chọn nhánh xóa
        setIsDeleteModalOpen(true);
        document
          .querySelector('.actions-' + nodeId)
          ?.classList.remove('staticNode');
      } else {
        const isConfirmed = window.confirm(
          'Bạn có chắc chắn muốn xóa node này không?'
        );

        if (!isConfirmed) return;

        // Tìm tất cả các edges có nodeId là source hoặc target
        const connectedEdges = edgeNode.filter(
          (edge) => edge.source === nodeId || edge.target === nodeId
        );

        console.log('connectedEdges', connectedEdges);

        const sourceNode = connectedEdges.find(
          (edge) => edge.target === nodeId
        )?.source;
        const targetNode = connectedEdges.find(
          (edge) => edge.source === nodeId
        )?.target;

        // Xóa node và các node con
        setNodes((nds) => {
          const updatedNodes = nds.filter((node) => node.id !== nodeId);

          // Cập nhật vị trí cho các node còn lại
          const sortedNodes = updatedNodes.sort(
            (a, b) => a.position.y - b.position.y
          );
          return sortedNodes.map((node, index) => ({
            ...node,
            position: {
              ...node.position,
              y: index * 110, // Khoảng cách giữa các node
            },
          }));
        });

        // Xóa các cạnh kết nối với node bị xóa và các node con
        setEdges((eds) =>
          eds.filter((edge) => edge.source !== nodeId && edge.target !== nodeId)
        );

        setEdges((eds) => [
          ...eds,
          {
            id: `new-edge-${sourceNode}-${targetNode}`,
            source: sourceNode,
            target: targetNode,
          },
        ]);
      }
    },
    [edges, setNodes, setEdges]
  );

  // Hàm xác định và xóa nhánh dựa trên node đã chọn
  const handleConfirmDeleteBranchNode = (branch) => {
    const allNode = store.getState();
    const Node = allNode.nodes;
    const edgeNode = allNode.edges;

    // Tìm node ifelse
    const ifelseNode = allNode.nodes.find((node) => node.id === deleteNodeId);

    // Tìm edges của nhánh được chọn (Yes hoặc No)
    const branchEdges = edgeNode.filter((edge) => edge.data?.label === branch);

    // Lấy ID của tất cả các node trong nhánh dựa trên các edges
    const branchNodeIds = branchEdges.map((edge) => edge.target);

    // Lấy danh sách các node trong nhánh dựa trên cùng tọa độ x với node được chọn
    const selectedNode = allNode.nodes.find(
      (node) => node.id === branchNodeIds[0]
    );
    const nodesToDelete = allNode.nodes
      .filter((node) => node.position.x === selectedNode.position.x) // Lọc các node có cùng tọa độ x với node được chọn
      .map((node) => node.id); // Lấy ID của các node trong nhánh

    // Bao gồm cả node ifelse trong danh sách node cần xóa
    nodesToDelete.push(ifelseNode.id);

    // Tìm edges nối đến nhánh còn lại
    const remainingEdges = edgeNode.filter(
      (edge) => edge.source === ifelseNode.id && edge.data?.label !== branch
    );

    const TargetIfelse = edgeNode.filter(
      (edge) => edge.target === ifelseNode.id
    );

    const NodeRemaining = allNode.nodes.find(
      (node) => node.id === remainingEdges[0].target
    );

    // Xóa tất cả các node trong nhánh
    setNodes((nds) => {
      const updatedNodes = nds.filter(
        (node) => !nodesToDelete.includes(node.id)
      );

      // Nếu còn node sau khi xóa
      if (updatedNodes.length > 0) {
        // Lấy tất cả các node của nhánh còn lại
        const nodesToRemaining = allNode.nodes
          .filter((node) => node.position.x === NodeRemaining.position.x) // Lọc các node có cùng tọa độ x với node được chọn
          .map((node) => node); // Lấy các node trong nhánh

        // Đặt lại vị trí của tất cả các node còn lại theo thứ tự và khoảng cách đều
        const updatedRemainingNodes = nodesToRemaining.map((node, index) => ({
          ...node,
          position: {
            x: ifelseNode.position.x,
            y: ifelseNode.position.y + index * 110,
          },
        }));

        // Kết hợp lại với các node khác (nếu có)
        return updatedNodes.map((node) => {
          const updatedNode = updatedRemainingNodes.find(
            (n) => n.id === node.id
          );
          return updatedNode ? updatedNode : node;
        });
      }

      return updatedNodes; // Trả về danh sách nodes đã được cập nhật
    });

    // Xóa các edges liên quan đến nhánh được chọn
    setEdges((eds) => {
      const updatedEdges = [
        ...eds.filter(
          (edge) =>
            !nodesToDelete.includes(edge.source) &&
            !nodesToDelete.includes(edge.target)
        ),
        {
          id: `edge-${NodeRemaining.id}-${TargetIfelse[0].source}`,
          source: NodeRemaining.id,
          target: TargetIfelse[0].source,
        },
      ];
      return updatedEdges;
    });

    setIsDeleteModalOpen(false); // Đóng modal
  };

  // Hàm xử lý xác nhận xóa
  const handleConfirmDelete = (choice) => {
    if (choice === 'yes') {
      handleConfirmDeleteBranchNode('Yes');
    } else if (choice === 'no') {
      handleConfirmDeleteBranchNode('No');
    } else if (choice === 'both') {
      handleConfirmDeleteBranchNode('Yes');
      handleConfirmDeleteBranchNode('No');
    }
  };

  // Hàm sửa node
  const handleEditNode = (nodeId: string) => {
    // Logic chỉnh sửa node
    alert(`Sửa node: ${nodeId}`);
  };

  const handleSave = () => {
    setShowPopupSuccess(true);

    setTimeout(() => {
      setShowPopupSuccess(false);
    }, 2000);
  };

  return (
    <div style={{ overflowY: 'auto', position: 'relative' }}>
      <div className="flex-flow">
        <MenuFlow />
        <div className="panelContainer">
          <ReactFlow
            nodes={nodes}
            edges={edges}
            edgeTypes={{ custom: CustomEdge }}
            onNodeClick={onNodeClick}
            onDrop={onDrop}
            onDragOver={onDragOver}
            panOnScroll
            defaultEdgeOptions={defaultEdgeOptions}
            onConnect={onConnect}
            onNodesChange={onNodesChange}
            onEdgesChange={onEdgesChange}
          >
            <Controls position="right-bottom" />
            <Background variant={BackgroundVariant.Lines} color="#ccccc" />
          </ReactFlow>
          <button className="btn-save" onClick={() => handleSave()}>
            Save
          </button>
        </div>
      </div>

      {isTabbarVisible && (
        <Tabbar addNode={addNode} closeTabbar={closeTabbar} />
      )}

      {showPopup && (
        <ShowPopup
          selectedNodeContent={selectedNodeContent}
          hidePopup={() => setShowPopup(false)}
        />
      )}

      {showPopupSuccess && (
        <div className="success-save">
          <div className="content-container">
            <div className="success-checkmark">
              <div className="check-icon">
                <span className="icon-line line-tip"></span>
                <span className="icon-line line-long"></span>
                <div className="icon-circle"></div>
                <div className="icon-fix"></div>
              </div>
            </div>
            <div className="text-center content-text text-30">
              Đã lưu lại tiến trình thành công !
            </div>
          </div>
        </div>
      )}

      {isDeleteModalOpen && (
        <DeleteNodeModal
          onConfirm={handleConfirmDelete}
          onClose={() => setIsDeleteModalOpen(false)}
        />
      )}
    </div>
  );
};

export default NodeFlow;
