import { useCallback, useEffect, useMemo, useState } from 'react';
import { Helmet } from 'react-helmet-async';
import { FormProvider, useForm } from 'react-hook-form';
import { useMutation, useQuery, useQueryClient } from 'react-query';
import { useLocation, useNavigate, useParams } from 'react-router';

import { yupResolver } from '@hookform/resolvers/yup';
import {
  applyNodeChanges,
  Background,
  type EdgeTypes,
  MarkerType,
  type Node,
  type NodeChange,
  type NodeTypes,
  ReactFlow,
  useReactFlow,
} from '@xyflow/react';

import '@xyflow/react/dist/style.css';

import { useDrawer } from '@material-hu/hooks/useDrawer';
import { useModal } from '@material-hu/hooks/useModal';
import { useSidesheet } from '@material-hu/hooks/useSidesheet';
import { IconArrowLeft, IconPencil } from '@material-hu/icons/tabler';
import IconButton from '@material-hu/mui/IconButton';
import Stack from '@material-hu/mui/Stack';
import { useTheme } from '@material-hu/mui/styles';
import Typography from '@material-hu/mui/Typography';

import Button from '@material-hu/components/design-system/Buttons/Button';
import HuDialog from '@material-hu/components/design-system/Dialog';
import HuPills from '@material-hu/components/design-system/Pills';
import HuCircularProgress from '@material-hu/components/design-system/ProgressIndicators/Spinner';
import HuSkeleton from '@material-hu/components/design-system/Skeleton';
import useHuSnackbar from '@material-hu/components/design-system/Snackbar';
import HuSwitcher from '@material-hu/components/design-system/Switcher';
import HuTooltip from '@material-hu/components/design-system/Tooltip';

import useHuGoTheme from 'src/hooks/useHuGoTheme';
import useHugoUnsavedWarning from 'src/hooks/useUnsavedWarning/altHugo';
import { ServiceItemStatus } from 'src/pages/dashboard/ServiceManagement/types';
import {
  activateWorkflow,
  deactivateWorkflow,
  getCatalogItem,
  getWorkflow,
  updateWorkflowContent,
  updateWorkflowInfo,
} from 'src/services/workflowsService';
import {
  type FlowEdge,
  type FlowNode,
  NodeType,
  type WorkflowError,
  type WorkflowForm,
  type WorkflowJson,
  WorkflowStatus,
  WorkflowsScreenSource,
} from 'src/types/workflows';
import { formatTitle } from 'src/utils/helmetUtils';
import { useLokaliseTranslation } from 'src/utils/i18n';
import { LogEvents, logEvent } from 'src/utils/logging';

import { validateBranches } from 'src/components/Condition/components/validations';

import { serviceManagementKeys } from '../ServiceManagement/queries';

import Branches from './components/Add/Branches';
import ChangeFieldAssignee from './components/Add/ChangeFieldAssignee';
import ChangeFieldStatus from './components/Add/ChangeFieldStatus';
import RequestApproval from './components/Add/RequestApproval';
import Task from './components/Add/Task';
import CustomControls from './components/CustomControls';
import CustomEdge from './components/CustomEdge';
import CustomNode from './components/CustomNode';
import InvalidNodesMenu from './components/InvalidNodesMenu';
import New from './components/New';
import SetTrigger from './components/SetTrigger';
import SidesheetContent from './components/SidesheetContent';
import { workflowsKeys } from './queries';
import { workflowsRoutes } from './routes';
import {
  addNode,
  antiTransformWorkflowBody,
  deleteNode,
  FIT_DURATION,
  FIT_NODES_LIMIT,
  getStatus,
  type InvalidNodeInfo,
  MIN_ZOOM,
  MOVEMENT_GRID,
  parseWorkflowErrors,
  realignNodes,
  roundPosition,
  transformWorkflowBody,
  updateNode,
  updateNodeName,
} from './utils';

const mapJsonFlow = (
  json: WorkflowJson,
): { nodes: FlowNode[]; edges: FlowEdge[] } => {
  const nodes: FlowNode[] = [];

  // Set edges
  const edges = json.edges?.map(edge => ({
    id: edge.id,
    source: edge.sourceId,
    target: edge.targetId,
    label: edge?.name || '',
    type: 'custom',
    markerEnd: { type: MarkerType.ArrowClosed },
  }));

  // Add start (trigger) node
  if (json.start) {
    nodes.push({
      id: json.start.id,
      data: {
        title: json.start.name || 'TRIGGER',
        type: NodeType.TRIGGER,
      },
      position: json.start.position || { x: 0, y: 0 },
      type: 'custom',
    });
  }

  // Add task nodes
  json.tasks?.forEach(task => {
    nodes.push({
      id: task.id,
      data: {
        title: task.name || 'Task',
        type: (task.type as NodeType) || NodeType.TASK,
      },
      position: task.position || { x: 0, y: 0 },
      type: 'custom',
    });
  });

  // Add conditional nodes
  json.conditionals?.forEach(conditional => {
    nodes.push({
      id: conditional.id,
      data: {
        title: conditional.name || 'Conditional',
        type: (conditional.type as NodeType) || NodeType.CONDITIONAL,
      },
      position: conditional.position || { x: 0, y: 0 },
      type: 'custom',
    });
  });

  // Add end nodes
  json.end?.forEach(end => {
    nodes.push({
      id: end.id,
      data: {
        type: NodeType.END,
      },
      position: end.position || { x: 0, y: 0 },
      type: 'custom',
    });
  });

  return { nodes, edges };
};

const Workflow = () => {
  const HuGoThemeProvider = useHuGoTheme();
  const theme = useTheme();
  const { t } = useLokaliseTranslation([
    'workflows',
    'general',
    'backoffice_only',
    'validations',
  ]);
  const { id: workflowId } = useParams();
  const [nodes, setNodes] = useState<FlowNode[]>([]);
  const [edges, setEdges] = useState<FlowEdge[]>([]);
  const [isReadOnly, setIsReadOnly] = useState(false);
  const [invalidNodes, setInvalidNodes] = useState<InvalidNodeInfo[]>([]);
  const [menuAnchorEl, setMenuAnchorEl] = useState<HTMLElement | null>(null);
  const [isTitleTruncated, setIsTitleTruncated] = useState(false);
  const [localTitle, setLocalTitle] = useState<string | null>(null);

  const addInvalidNode = useCallback((invalidNode: InvalidNodeInfo) => {
    setInvalidNodes(prev => {
      const filtered = prev.filter(node => node.id !== invalidNode.id);
      return [...filtered, invalidNode];
    });
  }, []);

  const removeInvalidNode = useCallback((nodeId: string) => {
    setInvalidNodes(prev => prev.filter(node => node.id !== nodeId));
  }, []);

  const navigate = useNavigate();
  const location = useLocation();
  const queryClient = useQueryClient();
  const { enqueueSnackbar } = useHuSnackbar();

  const [showDuplicateInfo, setShowDuplicateInfo] = useState(
    !!(location.state as { fromDuplicate?: boolean } | null)?.fromDuplicate,
  );

  const form = useForm<WorkflowForm>({
    defaultValues: {
      initialTrigger: null,
      trigger: null,
      body: {},
    },
    mode: 'onChange',
  });
  const { trigger, body } = form.watch();

  const setTrigger = (triggers: any) => {
    if (!triggers.length) return null;
    const { condition, name } = triggers[0];
    return {
      label: name,
      value: condition.ids[0],
    };
  };

  const { data, isLoading } = useQuery(
    workflowsKeys.workflow(workflowId),
    () => getWorkflow(workflowId || ''),
    {
      select: response => response.data,
      onSuccess: response => {
        const { nodes: mappedNodes, edges: mappedEdges } = mapJsonFlow(
          JSON.parse(response.hwlDefinition),
        );
        setNodes(mappedNodes);
        setEdges(mappedEdges);
        setInvalidNodes(parseWorkflowErrors(response.hwlErrors, mappedNodes));
        form.reset({
          initialTrigger: setTrigger(response.triggers),
          trigger: setTrigger(response.triggers),
          body: transformWorkflowBody(JSON.parse(response.hwlDefinition)),
        });
        titleForm.reset({
          title: response.workflow.name,
          description: response.workflow.description,
        });
        setIsActive(response.workflow.status === WorkflowStatus.ACTIVE);
      },
      onError: () => {
        navigate(workflowsRoutes.workflows());
      },
    },
  );

  const title = localTitle || data?.workflow.name;
  const status = data?.workflow.status;
  const isDraft = status === WorkflowStatus.DRAFT;

  const updateWorkflowMutation = useMutation(
    ({ publish }: { publish: boolean }) =>
      updateWorkflowContent(
        workflowId || '',
        trigger?.label || '',
        trigger?.value || '',
        antiTransformWorkflowBody(body),
        publish,
      ),
    {
      onSuccess: (_, { publish }) => {
        enqueueSnackbar({
          title:
            isDraft && publish
              ? t('workflow_published')
              : t('workflow_updated'),
          variant: 'success',
        });
        queryClient.invalidateQueries(workflowsKeys.workflow(workflowId));
        if (!publish) {
          logEvent(LogEvents.WORKFLOW_SAVED, { workflowId: workflowId });
        } else {
          logEvent(LogEvents.WORKFLOW_PUBLISHED, { workflowId: workflowId });
        }
      },
      onError: (
        error: {
          response: { data: { code: string; hwlErrors: WorkflowError[] } };
        },
        { publish },
      ) => {
        if (error.response.data.code === 'DUPLICATE_ENTITY') {
          enqueueSnackbar({
            title: t('duplicated_trigger.title'),
            description: t('duplicated_trigger.description', {
              name: trigger?.label,
            }),
            variant: 'error',
          });
        } else if (error.response.data.code === 'INVALID_PARAMETER') {
          enqueueSnackbar({
            title: t('publish_error'),
            description: t('publish_settings_error_description'),
            variant: 'error',
          });
          if (error.response.data.hwlErrors.length > 0) {
            setInvalidNodes(
              parseWorkflowErrors(error.response.data.hwlErrors, nodes),
            );
          }
        } else if (error.response.data.code === 'CATALOG_ITEM_NOT_FOUND') {
          enqueueSnackbar({
            title: t('trigger_deleted_error'),
            description: t('trigger_deleted_error_description'),
            variant: 'error',
          });
          form.setValue('trigger', null);
          form.setValue('initialTrigger', null);
        } else {
          enqueueSnackbar({
            title:
              isDraft && publish
                ? t('publish_error')
                : t('workflow_update_error'),
            description:
              isDraft && publish
                ? t('publish_error_description')
                : t('workflow_update_error_description'),
            variant: 'error',
          });
        }
      },
    },
  );

  const { getIntersectingNodes, fitView } = useReactFlow();

  const edgeTypes: EdgeTypes = useMemo(
    () => ({
      custom: props => (
        <CustomEdge
          {...props}
          parent={nodes.find(node => node.id === props.source)}
          showSidesheet={showSidesheet}
        />
      ),
    }),
    [nodes],
  );

  const nodeTypes: NodeTypes = useMemo(
    () => ({
      custom: props => (
        <CustomNode
          {...props}
          showChangeStatusDrawer={showChangeStatusDrawer}
          showChangeAssigneeDrawer={showChangeAssigneeDrawer}
          showBranchesDrawer={showBranchesDrawer}
          showApprovalDrawer={showApprovalDrawer}
          showTaskDrawer={showTaskDrawer}
          showSetTriggerDrawer={showSetTriggerDrawer}
          deleteNode={handleDeleteNode}
          updateNodeName={handleUpdateNodeName}
          invalidNodes={invalidNodes}
        />
      ),
    }),
    [invalidNodes],
  );

  const onNodeDrag = useCallback((_: React.MouseEvent, node: Node) => {
    const isOverlapping = getIntersectingNodes(node).length > 0;

    setNodes(ns =>
      ns.map((n: FlowNode) =>
        n.id === node.id
          ? ({ ...n, data: { ...n.data, overlap: isOverlapping } } as FlowNode)
          : n,
      ),
    );
  }, []);

  const onNodesChange = useCallback(
    (changes: NodeChange[]) =>
      setNodes(
        nds =>
          applyNodeChanges(
            changes.map((change: NodeChange) => {
              if (change.type === 'position') {
                const roundedPosition = roundPosition(
                  change.position?.x || 0,
                  change.position?.y || 0,
                  MOVEMENT_GRID,
                );
                updateNode(
                  form,
                  {
                    id: change.id,
                    position: roundedPosition,
                  },
                  t,
                );
                return { ...change, position: roundedPosition };
              }
              return change;
            }),
            nds as Node[],
          ) as FlowNode[],
      ),
    [],
  );

  const {
    modal: deleteModal,
    showModal: showDeleteModal,
    closeModal: closeDeleteModal,
  } = useModal<{ id: string; nodeType: NodeType }>(({ id, nodeType }) => (
    <HuDialog
      title={t(`delete_${nodeType}_sure`)}
      textBody={t(`delete_${nodeType}_body`)}
      primaryButtonProps={{
        children: t('general:delete'),
        onClick: () => {
          deleteNode(form, id, t, resetNodePositions, removeInvalidNode);
          closeDeleteModal();
        },
      }}
      secondaryButtonProps={{
        children: t('general:cancel'),
        onClick: closeDeleteModal,
      }}
      onClose={closeDeleteModal}
    />
  ));

  const handleDeleteNode = (nodeId: string) => {
    const nodeType = nodes.find(node => node.id === nodeId)?.data
      ?.type as NodeType;
    const hasBranches =
      nodeType === NodeType.CONDITIONAL || nodeType === NodeType.APPROVAL;
    if (hasBranches) showDeleteModal({ id: nodeId, nodeType });
    else deleteNode(form, nodeId, t, resetNodePositions, removeInvalidNode);
  };

  const handleUpdateNodeName = (nodeId: string, newName: string) => {
    updateNodeName(form, nodeId, newName, t, resetNodePositions);
  };

  const resetNodePositions = (
    newBody?: WorkflowJson,
    realign: boolean = true,
  ) => {
    const updatedBody = newBody ?? body;
    const realignedNodes = realign ? realignNodes(updatedBody) : updatedBody;
    form.setValue('body', realignedNodes, { shouldDirty: true });

    const { nodes: mappedNodes, edges: mappedEdges } =
      mapJsonFlow(realignedNodes);
    setNodes(mappedNodes);
    setEdges(mappedEdges);
  };

  /* Sidesheet handling */
  const showSidesheet = (edgeId?: string) => {
    setTimeout(() => {
      fitView({ duration: FIT_DURATION });
    }, 0.5);
    if (edgeId) addNode(form, edgeId, t, resetNodePositions);
    showAddComponentSidesheet();
  };

  const closeSidesheet = () => {
    const tasks = form.getValues('body').tasks || [];

    const nodeNew = tasks.find(node => node.type === NodeType.NEW);
    if (nodeNew) deleteNode(form, nodeNew.id, t, resetNodePositions);

    setTimeout(() => {
      fitView({ duration: FIT_DURATION });
    }, 0.5);
  };

  const {
    showDrawer: showAddComponentSidesheet,
    drawer: addComponentSidesheet,
    containerStyles,
  } = useSidesheet(
    SidesheetContent,
    {
      title: t('add_component'),
      whenClose: () => {
        closeSidesheet();
      },
      PaperProps: {
        sx: { mt: 8, pb: 8, width: 340 },
      },
    },
    {
      resetNodes: resetNodePositions,
      onInvalidNode: addInvalidNode,
      onValidNode: removeInvalidNode,
    },
  );

  const drawerForm = useForm<{ node: FlowNode | null }>({
    defaultValues: {
      node: null,
    },
    mode: 'onChange',
  });

  const { node: newNode } = drawerForm.watch();

  const {
    showDrawer: showChangeStatusDrawerInternal,
    drawer: changeStatusDrawer,
    closeDrawer: closeStatusDrawer,
  } = useDrawer(
    ChangeFieldStatus,
    {
      title: t('change_status'),
      primaryButtonProps: {
        children: t('general:update'),
        onClick: () => {
          if (newNode) {
            updateNode(
              form,
              newNode,
              t,
              resetNodePositions,
              addInvalidNode,
              removeInvalidNode,
            );
          }
          closeStatusDrawer();
        },
        fullWidth: true,
      },
      secondaryButtonProps: {
        children: t('general:cancel'),
        onClick: () => {
          closeStatusDrawer();
          drawerForm.reset();
        },
        fullWidth: true,
      },
    },
    {
      invalidNodes: invalidNodes,
    },
  );

  const {
    showDrawer: showChangeAssigneeDrawerInternal,
    drawer: changeAssigneeDrawer,
    closeDrawer: closeAssigneeDrawer,
  } = useDrawer(
    ChangeFieldAssignee,
    {
      title: t('change_assignee'),
      onClose: () => {
        closeAssigneeDrawer();
      },
      primaryButtonProps: {
        children: t('general:update'),
        onClick: () => {
          if (newNode) {
            updateNode(
              form,
              newNode,
              t,
              resetNodePositions,
              addInvalidNode,
              removeInvalidNode,
            );
          }
          closeAssigneeDrawer();
        },
        fullWidth: true,
      },
      secondaryButtonProps: {
        children: t('general:cancel'),
        onClick: () => {
          closeAssigneeDrawer();
          drawerForm.reset();
        },
        fullWidth: true,
      },
      slotProps: {
        layout: {
          sx: { pb: 1 },
        },
      },
    },
    {
      invalidNodes: invalidNodes,
    },
  );

  const {
    showDrawer: showApprovalDrawerInternal,
    drawer: approvalDrawer,
    closeDrawer: closeApprovalDrawer,
  } = useDrawer(RequestApproval, {
    title: t('request_approval'),
    primaryButtonProps: {
      children: t('general:add'),
      onClick: () => {
        updateNode(
          form,
          newNode,
          t,
          resetNodePositions,
          addInvalidNode,
          removeInvalidNode,
        );
        closeApprovalDrawer();
        closeSidesheet();
      },
      fullWidth: true,
      disabled: !drawerForm.getValues('node.name'),
    },
    secondaryButtonProps: {
      children: t('general:cancel'),
      onClick: () => {
        closeApprovalDrawer();
      },
      fullWidth: true,
    },
    onClose: () => {
      closeApprovalDrawer();
    },
    slotProps: {
      layout: {
        sx: { pb: 1 },
      },
    },
  });

  const {
    showDrawer: showTaskDrawerInternal,
    drawer: taskDrawer,
    closeDrawer: closeTaskDrawer,
  } = useDrawer(Task, {
    title: t('task'),
    primaryButtonProps: {
      children: t('general:update'),
      onClick: () => {
        const nodeData = { ...newNode };
        if (typeof nodeData.agentGroupId === 'object') {
          nodeData.agentGroupId = nodeData.agentGroupId?.id;
        }
        if (typeof nodeData.assigneeId === 'object') {
          nodeData.assigneeId = nodeData.assigneeId?.id;
        }
        updateNode(
          form,
          nodeData,
          t,
          resetNodePositions,
          addInvalidNode,
          removeInvalidNode,
        );
        drawerForm.reset();
        closeTaskDrawer();
        closeSidesheet();
      },
      fullWidth: true,
      disabled: !drawerForm.getValues('node.name'),
    },
    secondaryButtonProps: {
      children: t('general:cancel'),
      onClick: () => {
        closeTaskDrawer();
        drawerForm.reset();
      },
      fullWidth: true,
    },
    onClose: () => {
      closeTaskDrawer();
      drawerForm.reset();
    },
    slotProps: {
      layout: {
        sx: { pb: 1 },
      },
    },
  });

  // Wrap drawer to reset form with node data before opening
  const showChangeStatusDrawer = (node?: FlowNode) => {
    drawerForm.reset({ node: node || null });
    showChangeStatusDrawerInternal();
  };

  const showChangeAssigneeDrawer = (node?: FlowNode) => {
    drawerForm.reset({ node: node || null });
    showChangeAssigneeDrawerInternal();
  };

  const showBranchesDrawer = (node?: FlowNode) => {
    showBranchesDrawerInternal({ node: node, invalidNodes: invalidNodes });
  };

  const showApprovalDrawer = (node?: FlowNode) => {
    drawerForm.reset({ node: node || null });
    showApprovalDrawerInternal();
  };

  const showTaskDrawer = (node?: FlowNode) => {
    drawerForm.reset({ node: node || null });
    showTaskDrawerInternal();
  };

  const [editTrigger, setEditTrigger] = useState(false);

  const triggerForm = useForm({
    defaultValues: {
      trigger: form.getValues('trigger'),
    },
    mode: 'onChange',
  });

  const addTrigger = () => {
    form.setValue('trigger', triggerForm.getValues('trigger'), {
      shouldDirty: true,
    });
    closeSetTriggerDrawer();
  };

  const {
    showDrawer: showSetTriggerDrawerInternal,
    drawer: setTriggerDrawer,
    closeDrawer: closeSetTriggerDrawer,
  } = useDrawer(
    SetTrigger,
    {
      title: editTrigger ? t('update_trigger') : t('add_trigger'),
      footer: (
        <Button
          variant="primary"
          size="large"
          disabled={!triggerForm.watch('trigger')}
          onClick={() => addTrigger()}
        >
          {editTrigger ? t('update') : t('add')}
        </Button>
      ),
      onClose: () => {
        closeSetTriggerDrawer();
        triggerForm.reset({ trigger: form.getValues('trigger') });
      },
    },
    {},
  );

  const showSetTriggerDrawer = () => {
    const currentTrigger = form.getValues('trigger');
    setEditTrigger(!!currentTrigger);
    triggerForm.reset({ trigger: currentTrigger });
    showSetTriggerDrawerInternal();
  };

  const branchesForm = useForm({
    mode: 'onChange',
    resolver: yupResolver(validateBranches()),
  });

  const { node: newBranchesNode } = branchesForm.watch();

  const {
    showDrawer: showBranchesDrawerInternal,
    drawer: branchesDrawer,
    closeDrawer: closeBranchesDrawer,
  } = useDrawer(
    Branches,
    {
      title: t('branches_title'),
      primaryButtonProps: {
        children: t('general:update'),
        onClick: () => {
          if (newBranchesNode) {
            updateNode(
              form,
              newBranchesNode,
              t,
              resetNodePositions,
              addInvalidNode,
              removeInvalidNode,
            );
          }
          closeBranchesDrawer();
        },
        fullWidth: true,
      },
      secondaryButtonProps: {
        children: t('general:cancel'),
        onClick: () => {
          closeBranchesDrawer();
        },
        fullWidth: true,
      },
      onClose: () => {
        closeBranchesDrawer();
        branchesForm.reset();
      },
      slotProps: {
        layout: {
          sx: { pb: 1 },
        },
      },
    },
    {
      invalidNodes: invalidNodes,
      workflowForm: form,
    },
  );

  const {
    modal: updateModal,
    showModal: showUpdateModal,
    closeModal: closeUpdateModal,
  } = useModal(() => (
    <HuDialog
      title={t('update_sure')}
      textBody={t('update_sure_body')}
      primaryButtonProps={{
        children: t('update'),
        onClick: () =>
          updateWorkflowMutation.mutate(
            { publish: true },
            {
              onSettled: closeUpdateModal,
            },
          ),
        loading: updateWorkflowMutation.isLoading,
      }}
      secondaryButtonProps={{
        children: t('keep_editing'),
        onClick: () => closeUpdateModal(),
        sx: {
          ml: 30,
        },
      }}
      onClose={closeUpdateModal}
    />
  ));

  const {
    modal: publishModal,
    showModal: showPublishModal,
    closeModal: closePublishModal,
  } = useModal(() => (
    <HuDialog
      title={t('publish_sure')}
      textBody={t('publish_sure_body')}
      primaryButtonProps={{
        children: t('publish'),
        onClick: () =>
          updateWorkflowMutation.mutate(
            { publish: true },
            {
              onSettled: closePublishModal,
            },
          ),
      }}
      secondaryButtonProps={{
        children: t('general:cancel'),
        onClick: () => closePublishModal(),
        sx: {
          ml: 30,
        },
      }}
      onClose={closePublishModal}
    />
  ));

  const {
    modal: draftTriggerModal,
    showModal: showDraftTriggerModal,
    closeModal: closeDraftTriggerModal,
  } = useModal(() => (
    <HuDialog
      title={t('publish_draft.title')}
      textBody={t('publish_draft.description', { name: trigger?.label })}
      primaryButtonProps={{
        children: t('publish'),
        onClick: () =>
          updateWorkflowMutation.mutate(
            { publish: true },
            {
              onSettled: closeDraftTriggerModal,
            },
          ),
        loading: updateWorkflowMutation.isLoading,
      }}
      secondaryButtonProps={{
        disabled: updateWorkflowMutation.isLoading,
        children: t('general:cancel'),
        onClick: () => closeDraftTriggerModal(),
      }}
      onClose={closeDraftTriggerModal}
    />
  ));

  const {
    modal: duplicateInfoModal,
    showModal: showDuplicateInfoModal,
    closeModal: closeDuplicateInfoModal,
  } = useModal(() => (
    <HuDialog
      title={t('duplicate_info.title')}
      textBody={t('duplicate_info.description')}
      primaryButtonProps={{
        children: t('general:got_it'),
        onClick: () => {
          closeDuplicateInfoModal();
          showSetTriggerDrawer();
        },
      }}
      onClose={closeDuplicateInfoModal}
    />
  ));

  useEffect(() => {
    if (showDuplicateInfo) {
      showDuplicateInfoModal();
      setShowDuplicateInfo(false);
      navigate(location.pathname, { replace: true, state: {} });
    }
  }, [showDuplicateInfo, showDuplicateInfoModal, navigate, location.pathname]);

  const formNotDirty = !form.formState.isDirty;
  const incompleteFlow = invalidNodes.length > 0;
  const invalidFlow = useMemo(
    () => nodes.some(node => node.data?.type === NodeType.NEW),
    [nodes],
  );
  const canPublish = nodes.length > 2 && !!trigger;

  const { modal: UnsavedChangesModal, blocker } = useHugoUnsavedWarning({
    modalProps: {
      title: t('back_sure'),
      body: t('back_sure_body'),
      primaryButtonProps: {
        children: t('keep_editing'),
        onClick: () => {
          blocker?.reset?.();
          UnsavedChangesModal.closeModal();
        },
      },
      secondaryButtonProps: {
        children: t('backoffice_only:unsaved_warning.confirm'),
        onClick: () => {
          UnsavedChangesModal.closeModal();
          blocker?.proceed?.();
        },
        sx: {
          ml: 30,
        },
      },
    },
    shouldBlock: form.formState.isDirty,
  });

  const [isActive, setIsActive] = useState(status === WorkflowStatus.ACTIVE);

  const toggleWorkflowStatus = useMutation(
    (newIsActive: boolean) =>
      newIsActive
        ? activateWorkflow(workflowId || '')
        : deactivateWorkflow(workflowId || ''),
    {
      onMutate: newIsActive => {
        queryClient.cancelQueries(workflowsKeys.workflow(workflowId));
        const previousData = queryClient.getQueryData(
          workflowsKeys.workflow(workflowId),
        );

        queryClient.setQueryData(
          workflowsKeys.workflow(workflowId),
          (old: any) => ({
            ...old,
            data: {
              ...old.data,
              workflow: {
                ...old.data.workflow,
                status: newIsActive
                  ? WorkflowStatus.ACTIVE
                  : WorkflowStatus.INACTIVE,
              },
            },
          }),
        );

        setIsActive(newIsActive);
        return { previousData };
      },
      onSuccess: (_, newIsActive) => {
        queryClient.invalidateQueries(workflowsKeys.workflow(workflowId));
        enqueueSnackbar({
          title: newIsActive
            ? t('workflow_activated')
            : t('workflow_deactivated'),
          variant: 'success',
        });
        logEvent(LogEvents.WORKFLOW_STATUS_CHANGED, {
          workflowId: workflowId,
          workflow_status: newIsActive
            ? WorkflowStatus.ACTIVE
            : WorkflowStatus.INACTIVE,
          screen_source: WorkflowsScreenSource.WORKFLOW_BUILDER,
        });
      },
      onError: (_, newIsActive) => {
        queryClient.invalidateQueries(workflowsKeys.workflow(workflowId));
        setIsActive(!newIsActive);
        enqueueSnackbar({
          title: t('workflow_activation_error'),
          variant: 'error',
        });
      },
    },
  );

  const handleWorkflowStatus = () => {
    toggleWorkflowStatus.mutate(!isActive);
  };

  const { refetch: fetchCatalogItem, isFetching: isFetchingCatalogItem } =
    useQuery(
      serviceManagementKeys.serviceItems.detail(trigger?.value!),
      () => getCatalogItem(trigger?.value!),
      {
        enabled: false,
        onSuccess: response => {
          const serviceItem = response.data;
          if (serviceItem.status === ServiceItemStatus.DRAFT) {
            showDraftTriggerModal();
          } else {
            showPublishModal();
          }
        },
        onError: () => {
          showPublishModal();
        },
      },
    );

  const handlePublishClick = () => {
    if (!trigger?.value) return;
    fetchCatalogItem();
  };

  const fitOptions = () => {
    return nodes.length <= FIT_NODES_LIMIT && nodes.length > 0
      ? {
          maxZoom: 1,
          minZoom: 1,
          duration: 0,
        }
      : undefined;
  };

  const titleForm = useForm({
    defaultValues: {
      title: '',
      description: '',
    },
    mode: 'onChange',
  });

  const updateWorkflowInfoMutation = useMutation(
    () =>
      updateWorkflowInfo(
        workflowId || '',
        titleForm.getValues('title'),
        titleForm.getValues('description'),
      ),
    {
      onSuccess: () => {
        enqueueSnackbar({
          title: t('workflow_updated'),
          variant: 'success',
        });
        setLocalTitle(titleForm.getValues('title'));
      },
      onError: () => {
        enqueueSnackbar({
          title: t('workflow_update_error'),
          variant: 'error',
        });
      },
    },
  );

  const {
    showDrawer: showEditDrawer,
    drawer: editDrawer,
    closeDrawer,
  } = useDrawer(
    New,
    {
      title: t('edit_workflow_drawer'),
      primaryButtonProps: {
        children: t('general:update'),
        onClick: () => {
          updateWorkflowInfoMutation.mutate();
          closeDrawer();
        },
        fullWidth: true,
        disabled: !titleForm.formState.isValid || !titleForm.formState.isDirty,
      },
      secondaryButtonProps: {
        children: t('general:cancel'),
        onClick: () => {
          closeDrawer();
          titleForm.reset();
        },
        fullWidth: true,
      },
      onClose: () => {
        closeDrawer();
        titleForm.reset();
      },
    },
    {
      edit: true,
    },
  );

  return (
    <HuGoThemeProvider>
      <FormProvider {...drawerForm}>
        {changeStatusDrawer}
        {changeAssigneeDrawer}
        {approvalDrawer}
        {taskDrawer}
      </FormProvider>
      <FormProvider {...branchesForm}>{branchesDrawer}</FormProvider>
      <FormProvider {...triggerForm}>{setTriggerDrawer}</FormProvider>
      <FormProvider {...titleForm}>{editDrawer}</FormProvider>
      {publishModal}
      {updateModal}
      {draftTriggerModal}
      {duplicateInfoModal}
      {deleteModal}
      {UnsavedChangesModal.modal}
      <FormProvider {...form}>
        <Helmet>
          <title>{title && formatTitle(title)}</title>
        </Helmet>
        <Stack
          sx={{
            backgroundColor: ({ palette }) =>
              palette.new.background.layout.tertiary,
            borderBottom: '1px solid',
            borderColor: ({ palette }) => palette.new.border.neutral.default,
            justifyContent: 'space-between',
            flexDirection: 'row',
            alignItems: 'center',
            width: '100%',
            height: 64,
            gap: 1,
            px: 3,
            position: 'absolute',
            zIndex: 1000,
          }}
        >
          {isLoading && (
            <>
              <HuSkeleton
                variant="rounded"
                width={500}
                height={32}
              />
              <HuSkeleton
                variant="rounded"
                width={100}
                height={32}
              />
            </>
          )}
          {!isLoading && (
            <>
              <Stack
                sx={{
                  flexDirection: 'row',
                  justifyContent: 'flex-start',
                  alignItems: 'center',
                  gap: 2,
                }}
              >
                <IconButton
                  aria-label={t('general:back')}
                  onClick={() => navigate(workflowsRoutes.workflows())}
                >
                  <IconArrowLeft />
                </IconButton>
                <Stack
                  sx={{ flexDirection: 'row', alignItems: 'center', gap: 1 }}
                >
                  <HuTooltip
                    description={title || ''}
                    disableTooltip={!isTitleTruncated}
                  >
                    <Typography
                      ref={el =>
                        el &&
                        setIsTitleTruncated(el.scrollWidth > el.clientWidth)
                      }
                      variant="globalL"
                      fontWeight="fontWeightSemiBold"
                      sx={{
                        maxWidth: {
                          sm: 300,
                          lg: 600,
                        },
                        overflow: 'hidden',
                        textOverflow: 'ellipsis',
                        whiteSpace: 'nowrap',
                      }}
                    >
                      {title}
                    </Typography>
                  </HuTooltip>
                  <HuTooltip description={t('edit_workflow_drawer')}>
                    <Button
                      sx={{
                        minWidth: 36,
                        p: 0,
                      }}
                      variant="tertiary"
                      onClick={() => showEditDrawer()}
                    >
                      <IconPencil
                        style={{ width: 20 }}
                        color={theme.palette.new.text.neutral.default}
                      />
                    </Button>
                  </HuTooltip>
                </Stack>
                <HuPills
                  type={getStatus(status || '')}
                  hasIcon={false}
                  label={t('status', { context: status })}
                />
              </Stack>
              <Stack
                sx={{
                  gap: 2,
                  alignItems: 'center',
                  flexDirection: 'row',
                  justifyContent: 'flex-start',
                }}
              >
                {isDraft && (
                  <>
                    <HuTooltip
                      title={!trigger ? t('save_no_trigger.title') : undefined}
                      description={t(
                        !trigger
                          ? 'save_no_trigger.description'
                          : 'nothing_to_save',
                      )}
                      disableTooltip={
                        !!trigger && (!formNotDirty || invalidFlow)
                      }
                    >
                      <span>
                        <Button
                          variant="secondary"
                          disabled={formNotDirty || !trigger || invalidFlow}
                          loading={
                            !!(
                              updateWorkflowMutation.isLoading &&
                              !updateWorkflowMutation.variables?.publish
                            )
                          }
                          onClick={() =>
                            updateWorkflowMutation.mutate({ publish: false })
                          }
                        >
                          {t('general:save')}
                        </Button>
                      </span>
                    </HuTooltip>

                    <Stack
                      onMouseEnter={e => {
                        if (incompleteFlow) {
                          setMenuAnchorEl(e.currentTarget);
                        }
                      }}
                      onMouseLeave={() => setMenuAnchorEl(null)}
                      sx={{
                        cursor: incompleteFlow ? 'pointer' : 'default',
                      }}
                    >
                      <HuTooltip
                        title={t('publish_incomplete.title')}
                        description={t('publish_incomplete.description')}
                        disableTooltip={canPublish || incompleteFlow}
                      >
                        <span>
                          <Button
                            variant="primary"
                            disabled={
                              !canPublish || invalidFlow || incompleteFlow
                            }
                            loading={
                              !!(
                                updateWorkflowMutation.isLoading &&
                                updateWorkflowMutation.variables?.publish
                              ) || isFetchingCatalogItem
                            }
                            onClick={handlePublishClick}
                          >
                            {t('publish')}
                          </Button>
                        </span>
                      </HuTooltip>
                      <InvalidNodesMenu
                        anchorEl={menuAnchorEl}
                        invalidNodes={invalidNodes}
                        onClose={() => setMenuAnchorEl(null)}
                        workflowBody={body}
                        showChangeStatusDrawer={showChangeStatusDrawer}
                        showChangeAssigneeDrawer={showChangeAssigneeDrawer}
                        showBranchesDrawer={showBranchesDrawer}
                        showApprovalDrawer={showApprovalDrawer}
                        showTaskDrawer={showTaskDrawer}
                      />
                    </Stack>
                  </>
                )}
                {!isDraft && (
                  <>
                    <HuSwitcher
                      value={isActive}
                      onChange={() => handleWorkflowStatus()}
                      disabled={!formNotDirty}
                      disabledTooltip={{
                        description: !formNotDirty
                          ? t('update_before_toggle')
                          : t('toggle', {
                              context: (!isActive).toString(),
                            }),
                        direction: 'bottom',
                      }}
                    />

                    <Stack
                      onMouseEnter={e => {
                        if (incompleteFlow) {
                          setMenuAnchorEl(e.currentTarget);
                        }
                      }}
                      onMouseLeave={() => setMenuAnchorEl(null)}
                      sx={{
                        cursor: incompleteFlow ? 'pointer' : 'default',
                      }}
                    >
                      <Button
                        variant="primary"
                        disabled={formNotDirty || invalidFlow || incompleteFlow}
                        loading={updateWorkflowMutation.isLoading}
                        onClick={() => showUpdateModal()}
                      >
                        {t('update')}
                      </Button>
                      <InvalidNodesMenu
                        anchorEl={menuAnchorEl}
                        invalidNodes={invalidNodes}
                        onClose={() => setMenuAnchorEl(null)}
                        workflowBody={body}
                        showChangeStatusDrawer={showChangeStatusDrawer}
                        showChangeAssigneeDrawer={showChangeAssigneeDrawer}
                        showBranchesDrawer={showBranchesDrawer}
                        showApprovalDrawer={showApprovalDrawer}
                        showTaskDrawer={showTaskDrawer}
                      />
                    </Stack>
                  </>
                )}
              </Stack>
            </>
          )}
        </Stack>
        <div style={{ ...containerStyles, paddingTop: 64 }}>
          {isLoading && (
            <Stack
              sx={{
                width: '100%',
                height: '100%',
                justifyContent: 'center',
                alignItems: 'center',
              }}
            >
              <HuCircularProgress size={42} />
            </Stack>
          )}
          {!isLoading && (
            <ReactFlow
              nodes={nodes as Node[]}
              edges={edges}
              onNodeDrag={onNodeDrag}
              onNodesChange={onNodesChange}
              nodeTypes={nodeTypes}
              edgeTypes={edgeTypes}
              proOptions={{ hideAttribution: true }}
              fitView
              fitViewOptions={fitOptions() as any}
              minZoom={MIN_ZOOM}
              nodesDraggable={false}
              deleteKeyCode={null}
              elementsSelectable={!isReadOnly}
            >
              <Background />
              <CustomControls setReadOnly={setIsReadOnly} />
            </ReactFlow>
          )}
          {addComponentSidesheet}
        </div>
      </FormProvider>
    </HuGoThemeProvider>
  );
};

export default Workflow;
