'use client'

import type { StepByStepTourGuide } from './target-registry'
import type {
  StepByStepTourGuideGroup,
  StepByStepTourTaskId,
  StepByStepTourTaskView,
} from './types'
import { Button } from '@langgenius/dify-ui/button'
import { cn } from '@langgenius/dify-ui/cn'
import { Popover, PopoverContent } from '@langgenius/dify-ui/popover'
import { useSuspenseQuery } from '@tanstack/react-query'
import { useAtomValue, useSetAtom } from 'jotai'
import { useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { buildIntegrationPath } from '@/app/components/integrations/routes'
import { useDocLink } from '@/context/i18n'
import { useModalContextSelector } from '@/context/modal-context'
import { workspacePermissionKeysAtom } from '@/context/permission-state'
import { currentWorkspaceAtom, isCurrentWorkspaceManagerAtom } from '@/context/workspace-state'
import { systemFeaturesQueryOptions } from '@/features/system-features/client'
import { usePathname, useRouter } from '@/next/navigation'
import { hasPermission } from '@/utils/permission'
import { getStepByStepTourPermissionVariant, trackStepByStepTourEvent } from './analytics'
import { StepByStepTourCoachmark } from './coachmark'
import { FloatingChecklist } from './floating-widget'
import {
  activeStepByStepTourGuideGroupAtom,
  activeStepByStepTourGuideIndexAtom,
  activeStepByStepTourGuideIndexesAtom,
  activeStepByStepTourTaskIdAtom,
  advanceStepByStepTourGuideAtom,
  completedStepByStepTourTaskIdsAtom,
  completeStepByStepTourTaskAtom,
  resetStepByStepTourSessionAtom,
  skipStepByStepTourAtom,
  startStepByStepTourTaskAtom,
  stepByStepTourEnabledForCurrentWorkspaceAtom,
  stepByStepTourFirstWorkspaceIdAtom,
  stepByStepTourSkippedAtom,
  stepByStepTourSkipRecoveryVisibleAtom,
  uncompleteStepByStepTourTaskAtom,
} from './state'
import { useSetStepByStepTourShellMode, useStepByStepTourShellModeValue } from './storage'
import {
  getStepByStepTourGuideInteractionPolicy,
  getStepByStepTourGuideKind,
  getStepByStepTourGuides,
  getStepByStepTourTargetSelector,
  STEP_BY_STEP_TOUR_TARGETS,
} from './target-registry'
import { STEP_BY_STEP_TOUR_TASKS } from './tasks'
import { useStepByStepTourTarget } from './use-tour-target'

type StepByStepTourTask = (typeof STEP_BY_STEP_TOUR_TASKS)[number]

const hasCompletedAllStepByStepTourTasks = (
  completedTaskIds: StepByStepTourTaskId[],
  tasks: readonly StepByStepTourTask[],
) => tasks.every((task) => completedTaskIds.includes(task.id))

const isPermissionFallbackGuideGroup = (
  guideGroup: StepByStepTourGuideGroup | undefined,
): guideGroup is Extract<
  StepByStepTourGuideGroup,
  'homeNoCreate' | 'integrationLimitedAccess' | 'studioNoCreateEmpty' | 'studioNoCreateWithApps'
> =>
  guideGroup === 'homeNoCreate' ||
  guideGroup === 'integrationLimitedAccess' ||
  guideGroup === 'studioNoCreateEmpty' ||
  guideGroup === 'studioNoCreateWithApps'

const shouldHideOnPathname = (pathname: string) =>
  pathname.startsWith('/app/') || pathname.includes('/installed/')

const isGuideEligibleForPlan = (guide: StepByStepTourGuide, canSetPluginPreferences: boolean) =>
  guide.target !== STEP_BY_STEP_TOUR_TARGETS.integrationUpdateSettings || canSetPluginPreferences

const isOptionalGuideTargetAvailable = (guide: StepByStepTourGuide, pathname: string) => {
  if (!guide.optional) return true

  if (guide.integrationSection && pathname !== buildIntegrationPath(guide.integrationSection))
    return true

  if (typeof document === 'undefined') return true

  return Boolean(document.querySelector(getStepByStepTourTargetSelector(guide.target)))
}

const isElementVerticallyVisible = (element: HTMLElement) => {
  const rect = element.getBoundingClientRect()
  const viewportHeight = window.innerHeight || document.documentElement.clientHeight

  return rect.top >= 0 && rect.bottom <= viewportHeight
}

const scrollTourTargetIntoView = (element: HTMLElement) => {
  if (isElementVerticallyVisible(element)) return

  element.scrollIntoView({
    block: 'nearest',
    behavior: 'auto',
  })
}

const createGuideIndexes = (guides: StepByStepTourGuide[]) => guides.map((_, index) => index)

const getActiveGuideIndexes = (
  guides: StepByStepTourGuide[],
  guideIndexes: number[] | undefined,
) => {
  const fallbackGuideIndexes = createGuideIndexes(guides)

  if (!guideIndexes?.length) return fallbackGuideIndexes

  const validGuideIndexes = guideIndexes.filter((index) => index >= 0 && index < guides.length)
  return validGuideIndexes.length > 0 ? validGuideIndexes : fallbackGuideIndexes
}

type StepByStepTourMountProps = {
  className?: string
}

export default function StepByStepTourMount({ className }: StepByStepTourMountProps) {
  const router = useRouter()
  const pathname = usePathname()
  const docLink = useDocLink()
  const { t } = useTranslation('common')
  const currentWorkspace = useAtomValue(currentWorkspaceAtom)
  const isCurrentWorkspaceManager = useAtomValue(isCurrentWorkspaceManagerAtom)
  const workspacePermissionKeys = useAtomValue(workspacePermissionKeysAtom)
  const hasBlockingModalOpen = useModalContextSelector((state) => state.hasBlockingModalOpen)
  const { data: systemFeatures } = useSuspenseQuery(systemFeaturesQueryOptions())
  const completedTaskIds = useAtomValue(completedStepByStepTourTaskIdsAtom)
  const skipped = useAtomValue(stepByStepTourSkippedAtom)
  const firstWorkspaceId = useAtomValue(stepByStepTourFirstWorkspaceIdAtom)
  const enabledForCurrentWorkspace = useAtomValue(stepByStepTourEnabledForCurrentWorkspaceAtom)
  const activeTaskId = useAtomValue(activeStepByStepTourTaskIdAtom)
  const sessionGuideIndex = useAtomValue(activeStepByStepTourGuideIndexAtom)
  const sessionGuideGroup = useAtomValue(activeStepByStepTourGuideGroupAtom)
  const sessionGuideIndexes = useAtomValue(activeStepByStepTourGuideIndexesAtom)
  const skipRecoveryVisible = useAtomValue(stepByStepTourSkipRecoveryVisibleAtom)
  const setSkipRecoveryVisible = useSetAtom(stepByStepTourSkipRecoveryVisibleAtom)
  const advanceGuide = useSetAtom(advanceStepByStepTourGuideAtom)
  const completeTask = useSetAtom(completeStepByStepTourTaskAtom)
  const resetSession = useSetAtom(resetStepByStepTourSessionAtom)
  const patchSkipTour = useSetAtom(skipStepByStepTourAtom)
  const startTask = useSetAtom(startStepByStepTourTaskAtom)
  const uncompleteTask = useSetAtom(uncompleteStepByStepTourTaskAtom)
  const shellMode = useStepByStepTourShellModeValue()
  const setShellMode = useSetStepByStepTourShellMode()
  const anchorRef = useRef<HTMLDivElement>(null)
  const lastRequestedIntegrationRouteRef = useRef<string | undefined>(undefined)
  const previousSkippedRef = useRef(skipped)
  const permissionFallbackAnalyticsKeyRef = useRef<string | undefined>(undefined)
  const shownAnalyticsKeyRef = useRef<string | undefined>(undefined)
  const skipTimeoutRef = useRef<number | undefined>(undefined)
  const stepShownAnalyticsKeyRef = useRef<string | undefined>(undefined)
  const [checklistExiting, setChecklistExiting] = useState(false)
  const currentWorkspaceId = currentWorkspace.id
  const canCreateApp = hasPermission(workspacePermissionKeys, 'app.create_and_management')
  const homeGuideGroup: Extract<StepByStepTourGuideGroup, 'homeNoCreate'> | undefined = canCreateApp
    ? undefined
    : 'homeNoCreate'
  const hasKnowledgeWalkthroughPermissions =
    hasPermission(workspacePermissionKeys, 'dataset.create_and_management') &&
    hasPermission(workspacePermissionKeys, 'dataset.external.connect')
  const canSetPluginPreferences = hasPermission(
    workspacePermissionKeys,
    'plugin.plugin_preferences',
  )
  const integrationGuideGroup:
    | Extract<StepByStepTourGuideGroup, 'integrationLimitedAccess'>
    | undefined = isCurrentWorkspaceManager ? undefined : 'integrationLimitedAccess'
  const hasIntegrationWalkthroughPermissions = !integrationGuideGroup

  useEffect(
    () => () => {
      if (skipTimeoutRef.current) window.clearTimeout(skipTimeoutRef.current)
    },
    [],
  )

  const learnDifyEnabled = systemFeatures.enable_learn_app
  const stepByStepTourFeatureEnabled = systemFeatures.enable_step_by_step_tour
  const availableTasks = learnDifyEnabled
    ? STEP_BY_STEP_TOUR_TASKS
    : STEP_BY_STEP_TOUR_TASKS.filter((task) => task.id !== 'home')
  const availableTaskIds = availableTasks.map((task) => task.id)
  const completedAvailableTaskIds = completedTaskIds.filter((taskId) =>
    availableTaskIds.includes(taskId),
  )
  const allTasksCompleted = hasCompletedAllStepByStepTourTasks(completedTaskIds, availableTasks)
  const currentTask = availableTasks.find((task) => !completedTaskIds.includes(task.id))
  const activeTask = activeTaskId
    ? availableTasks.find((task) => task.id === activeTaskId)
    : undefined
  const activeGuideGroup: StepByStepTourGuideGroup | undefined =
    activeTask?.id === 'home'
      ? homeGuideGroup
      : activeTask?.id === 'integration'
        ? integrationGuideGroup
        : sessionGuideGroup
  const activeGuides = activeTask ? getStepByStepTourGuides(activeTask.id, activeGuideGroup) : []
  const activeGuideIndex = sessionGuideIndex ?? 0
  const activeGuide = activeGuides[activeGuideIndex]
  const hasActiveGuide = Boolean(activeTask && activeGuide)
  const minimized = Boolean(activeTask) || shellMode === 'collapsed'
  const activeGuideIndexes =
    activeGuides.length > 0
      ? getActiveGuideIndexes(activeGuides, sessionGuideIndexes)
          .filter((index) => isGuideEligibleForPlan(activeGuides[index]!, canSetPluginPreferences))
          .filter((index) => isOptionalGuideTargetAvailable(activeGuides[index]!, pathname))
      : []
  const activeGuidePlanIndex = activeGuideIndexes.findIndex((index) => index === activeGuideIndex)
  const activeStepIndex =
    activeGuideIndexes.length > 0
      ? activeGuidePlanIndex === -1
        ? activeGuideIndexes.filter((index) => index < activeGuideIndex).length
        : activeGuidePlanIndex
      : activeGuideIndex
  const activeStepTotal = activeGuideIndexes.length || activeGuides.length
  const activeGuideAnalyticsProperties =
    activeTask && activeGuide
      ? {
          task_id: activeTask.id,
          guide_id: activeGuide.id,
        }
      : undefined
  const visible =
    systemFeatures.deployment_edition === 'CLOUD' &&
    stepByStepTourFeatureEnabled &&
    enabledForCurrentWorkspace &&
    (hasActiveGuide || !shouldHideOnPathname(pathname))
  const overlayVisible = visible && !hasBlockingModalOpen
  const completionPromptVisible = visible && allTasksCompleted && !activeTask
  const checklistMinimized = completionPromptVisible ? false : minimized
  const expanded = !checklistMinimized
  const activeTargetElement = useStepByStepTourTarget(activeGuide?.target)
  const activeGuidePlacement =
    activeGuide?.target === STEP_BY_STEP_TOUR_TARGETS.studioEmptyLearnDify
      ? 'top'
      : activeGuide?.target === STEP_BY_STEP_TOUR_TARGETS.integration
        ? 'right'
        : 'bottom'
  const getPermissionVariant = (taskId: StepByStepTourTaskId) =>
    getStepByStepTourPermissionVariant({
      canCreateApp,
      hasIntegrationWalkthroughPermissions,
      hasKnowledgeWalkthroughPermissions,
      taskId,
    })

  const trackTaskCompleted = (
    completedTaskIds: StepByStepTourTaskId[],
    taskId: StepByStepTourTaskId,
  ) => {
    const completedAvailableTaskIds = completedTaskIds.filter((completedTaskId) =>
      availableTaskIds.includes(completedTaskId),
    )

    trackStepByStepTourEvent({
      action: 'task_completed',
      task_id: taskId,
      completed_task_count: completedAvailableTaskIds.length,
      permission_variant: getPermissionVariant(taskId),
      task_total: availableTasks.length,
    })

    if (hasCompletedAllStepByStepTourTasks(completedTaskIds, availableTasks)) {
      trackStepByStepTourEvent({
        action: 'tour_completed',
        completed_task_count: completedAvailableTaskIds.length,
        task_total: availableTasks.length,
      })
    }
  }

  const trackTourSkipped = (completedTaskIds: StepByStepTourTaskId[]) => {
    trackStepByStepTourEvent({
      action: 'tour_skipped',
      task_id: activeTask?.id,
      completed_task_count: completedTaskIds.filter((taskId) => availableTaskIds.includes(taskId))
        .length,
    })
  }

  useEffect(() => {
    if (activeTask?.id !== 'integration' || !activeGuide?.integrationSection) return

    const activeGuideRoute = buildIntegrationPath(activeGuide.integrationSection)
    if (pathname === activeGuideRoute) {
      lastRequestedIntegrationRouteRef.current = undefined
      return
    }

    if (lastRequestedIntegrationRouteRef.current === activeGuideRoute) return

    lastRequestedIntegrationRouteRef.current = activeGuideRoute
    router.push(activeGuideRoute)
  }, [activeGuide?.integrationSection, activeTask?.id, pathname, router])

  useEffect(() => {
    if (!activeTargetElement) return

    scrollTourTargetIntoView(activeTargetElement)
  }, [activeGuide?.target, activeTargetElement])

  useEffect(() => {
    if (!visible) return

    const entryPoint = previousSkippedRef.current
      ? 'reenabled_after_skip'
      : firstWorkspaceId === currentWorkspaceId
        ? 'first_workspace'
        : 'help_menu_enabled'
    const shownAnalyticsKey = `${currentWorkspaceId}:${entryPoint}`
    if (shownAnalyticsKeyRef.current === shownAnalyticsKey) return

    shownAnalyticsKeyRef.current = shownAnalyticsKey
    trackStepByStepTourEvent({
      action: 'tour_shown',
      completed_task_count: completedAvailableTaskIds.length,
      entry_point: entryPoint,
      task_total: availableTasks.length,
    })
  }, [
    availableTasks.length,
    completedAvailableTaskIds.length,
    currentWorkspaceId,
    firstWorkspaceId,
    visible,
  ])

  useEffect(() => {
    if (!visible || !activeTask || !activeGuide || !activeTargetElement) return

    const guideAnalyticsProperties = { task_id: activeTask.id, guide_id: activeGuide.id }

    const stepShownAnalyticsKey = [
      currentWorkspaceId,
      guideAnalyticsProperties.task_id,
      guideAnalyticsProperties.guide_id,
    ].join(':')
    if (stepShownAnalyticsKeyRef.current === stepShownAnalyticsKey) return

    stepShownAnalyticsKeyRef.current = stepShownAnalyticsKey
    trackStepByStepTourEvent({
      action: 'guide_shown',
      task_id: guideAnalyticsProperties.task_id,
      guide_id: guideAnalyticsProperties.guide_id,
    })
  }, [
    activeGuide,
    activeGuideGroup,
    activeStepIndex,
    activeStepTotal,
    activeTargetElement,
    activeTask,
    currentWorkspaceId,
    visible,
  ])

  useEffect(() => {
    if (!visible) return

    if (currentTask?.id === 'knowledge' && !hasKnowledgeWalkthroughPermissions) {
      const fallbackAnalyticsKey = `${currentWorkspaceId}:knowledge:no_knowledge_permission`
      if (permissionFallbackAnalyticsKeyRef.current === fallbackAnalyticsKey) return

      permissionFallbackAnalyticsKeyRef.current = fallbackAnalyticsKey
      trackStepByStepTourEvent({
        action: 'permission_fallback_shown',
        task_id: 'knowledge',
        permission_variant: 'no_knowledge_permission',
      })
      return
    }

    if (!activeTask) return

    if (!isPermissionFallbackGuideGroup(activeGuideGroup)) return

    const fallbackAnalyticsKey = `${currentWorkspaceId}:${activeTask.id}:${activeGuideGroup}`
    if (permissionFallbackAnalyticsKeyRef.current === fallbackAnalyticsKey) return

    permissionFallbackAnalyticsKeyRef.current = fallbackAnalyticsKey
    trackStepByStepTourEvent({
      action: 'permission_fallback_shown',
      task_id: activeTask.id,
      permission_variant:
        activeTask.id === 'integration' ? 'no_integration_permission' : 'no_create',
    })
  }, [
    activeGuideGroup,
    activeTask,
    currentTask?.id,
    currentWorkspaceId,
    hasKnowledgeWalkthroughPermissions,
    visible,
  ])

  useEffect(() => {
    previousSkippedRef.current = skipped
  }, [skipped])

  if (!visible && !skipRecoveryVisible) return null
  const title = t(($) => $['stepByStepTour.title'])
  const taskCopy: Record<
    StepByStepTourTaskId,
    Pick<StepByStepTourTaskView, 'title' | 'description' | 'primaryActionLabel'>
  > = {
    home: {
      title: canCreateApp
        ? t(($) => $['stepByStepTour.tasks.home.title'])
        : t(($) => $['stepByStepTour.tasks.home.noCreate.title']),
      description: canCreateApp
        ? t(($) => $['stepByStepTour.tasks.home.description'])
        : t(($) => $['stepByStepTour.tasks.home.noCreate.description']),
      primaryActionLabel: t(($) => $['stepByStepTour.tasks.home.primaryActionLabel']),
    },
    studio: {
      title: canCreateApp
        ? t(($) => $['stepByStepTour.tasks.studio.title'])
        : t(($) => $['stepByStepTour.tasks.studio.noCreate.title']),
      description: canCreateApp
        ? t(($) => $['stepByStepTour.tasks.studio.description'])
        : t(($) => $['stepByStepTour.tasks.studio.noCreate.description']),
      primaryActionLabel: t(($) => $['stepByStepTour.tasks.studio.primaryActionLabel']),
    },
    knowledge: {
      title: hasKnowledgeWalkthroughPermissions
        ? t(($) => $['stepByStepTour.tasks.knowledge.title'])
        : t(($) => $['stepByStepTour.tasks.knowledge.noPermission.title']),
      description: hasKnowledgeWalkthroughPermissions
        ? t(($) => $['stepByStepTour.tasks.knowledge.description'])
        : t(($) => $['stepByStepTour.tasks.knowledge.noPermission.description']),
      primaryActionLabel: hasKnowledgeWalkthroughPermissions
        ? t(($) => $['stepByStepTour.tasks.knowledge.primaryActionLabel'])
        : t(($) => $['stepByStepTour.tasks.knowledge.noPermission.primaryActionLabel']),
    },
    integration: {
      title: hasIntegrationWalkthroughPermissions
        ? t(($) => $['stepByStepTour.tasks.integration.title'])
        : t(($) => $['stepByStepTour.tasks.integration.noPermission.title']),
      description: hasIntegrationWalkthroughPermissions
        ? t(($) => $['stepByStepTour.tasks.integration.description'])
        : t(($) => $['stepByStepTour.tasks.integration.noPermission.description']),
      primaryActionLabel: t(($) => $['stepByStepTour.tasks.integration.primaryActionLabel']),
    },
  }
  const tasks = availableTasks.map((task): StepByStepTourTaskView => {
    const completed = completedTaskIds.includes(task.id)
    const knowledgeUnavailable = task.id === 'knowledge' && !hasKnowledgeWalkthroughPermissions

    return {
      ...taskCopy[task.id],
      id: task.id,
      iconClassName: knowledgeUnavailable ? 'i-ri-lock-line' : task.iconClassName,
      status: completed ? 'completed' : task.id === currentTask?.id ? 'current' : 'pending',
      canToggleCompletion: false,
    }
  })

  const skipTour = () => {
    if (checklistExiting) return

    setChecklistExiting(true)

    skipTimeoutRef.current = window.setTimeout(() => {
      patchSkipTour({
        onSuccess: trackTourSkipped,
        onError: () => {
          setChecklistExiting(false)
          setSkipRecoveryVisible(false)
        },
      })
      setChecklistExiting(false)
      setSkipRecoveryVisible(true)
    }, 160)
  }

  const skipActiveGuide = () => {
    const guideAnalyticsProperties = activeGuideAnalyticsProperties
    if (guideAnalyticsProperties) {
      trackStepByStepTourEvent({
        action: 'guide_skipped',
        task_id: guideAnalyticsProperties.task_id,
        guide_id: guideAnalyticsProperties.guide_id,
      })
    }

    resetSession()
    setShellMode('expanded')
  }

  const getNextVisibleActiveGuideIndex = (startIndex: number) => {
    if (activeGuideIndexes.length > 0) {
      let nextGuideIndexes = activeGuideIndexes
      let nextGuideIndex = nextGuideIndexes.find((index) => index >= startIndex)

      while (nextGuideIndex !== undefined) {
        if (
          isGuideEligibleForPlan(activeGuides[nextGuideIndex]!, canSetPluginPreferences) &&
          isOptionalGuideTargetAvailable(activeGuides[nextGuideIndex]!, pathname)
        ) {
          return { activeGuideIndex: nextGuideIndex, activeGuideIndexes: nextGuideIndexes }
        }

        nextGuideIndexes = nextGuideIndexes.filter((index) => index !== nextGuideIndex)
        nextGuideIndex = nextGuideIndexes.find((index) => index >= startIndex)
      }

      return { activeGuideIndex: -1, activeGuideIndexes: nextGuideIndexes }
    }

    for (let index = startIndex; index < activeGuides.length; index += 1) {
      if (
        isGuideEligibleForPlan(activeGuides[index]!, canSetPluginPreferences) &&
        isOptionalGuideTargetAvailable(activeGuides[index]!, pathname)
      ) {
        return { activeGuideIndex: index, activeGuideIndexes: undefined }
      }
    }

    return { activeGuideIndex: -1, activeGuideIndexes: undefined }
  }

  const completeActiveGuide = () => {
    if (!activeTask || !activeGuide) return

    if (activeGuide.completionMode === 'external') return

    const guideAnalyticsProperties = activeGuideAnalyticsProperties
    if (guideAnalyticsProperties) {
      trackStepByStepTourEvent({
        action: 'guide_completed',
        task_id: guideAnalyticsProperties.task_id,
        guide_id: guideAnalyticsProperties.guide_id,
      })
    }

    if (activeGuideIndex < activeGuides.length - 1) {
      const nextActiveGuide = getNextVisibleActiveGuideIndex(activeGuideIndex + 1)

      if (nextActiveGuide.activeGuideIndex === -1) {
        completeTask({
          taskId: activeTask.id,
          onSuccess: (completedTaskIds) => trackTaskCompleted(completedTaskIds, activeTask.id),
        })
        resetSession()
        setShellMode('expanded')
        return
      }

      advanceGuide({
        guideIndex: nextActiveGuide.activeGuideIndex,
        guideIndexes: nextActiveGuide.activeGuideIndexes,
      })
      return
    }

    completeTask({
      taskId: activeTask.id,
      onSuccess: (completedTaskIds) => trackTaskCompleted(completedTaskIds, activeTask.id),
    })
    resetSession()
    setShellMode('expanded')
  }

  const dismissCompletedTour = () => {
    patchSkipTour({
      onSuccess: trackTourSkipped,
    })
    resetSession()
    setShellMode('expanded')
  }

  const floatingChecklist = (
    <FloatingChecklist
      title={title}
      duration={t(($) => $['stepByStepTour.duration'])}
      minimized={checklistMinimized}
      progress={{
        ariaValueText: t(($) => $['stepByStepTour.progressAriaValueText'], {
          completed: completedAvailableTaskIds.length,
          total: availableTasks.length,
        }),
        completed: completedAvailableTaskIds.length,
        total: availableTasks.length,
      }}
      completionPrompt={
        completionPromptVisible
          ? {
              label: t(($) => $['stepByStepTour.completion.label']),
              title: t(($) => $['stepByStepTour.completion.title']),
              description: t(($) => $['stepByStepTour.completion.description']),
              dismissLabel: t(($) => $['stepByStepTour.completion.dismiss']),
              onDismiss: dismissCompletedTour,
            }
          : undefined
      }
      tasks={tasks}
      skipLabel={t(($) => $['stepByStepTour.skip'])}
      minimizeLabel={t(($) => $['stepByStepTour.minimize'])}
      restoreLabel={t(($) => $['stepByStepTour.restore'])}
      getTaskCompleteLabel={(taskTitle) =>
        t(($) => $['stepByStepTour.markTaskComplete'], { title: taskTitle })
      }
      getTaskIncompleteLabel={(taskTitle) =>
        t(($) => $['stepByStepTour.markTaskIncomplete'], { title: taskTitle })
      }
      onMinimize={() => {
        setShellMode('collapsed')
      }}
      onRestore={() => {
        setShellMode('expanded')
      }}
      onSkip={skipTour}
      onCompleteTask={(taskId) => {
        const guides = getStepByStepTourGuides(taskId, sessionGuideGroup)
        const hasExternalCompletionGuide = guides.some(
          (guide) => getStepByStepTourGuideKind(guide) === 'action',
        )
        if (hasExternalCompletionGuide) return

        completeTask({
          taskId,
          onSuccess: (completedTaskIds) => trackTaskCompleted(completedTaskIds, taskId),
        })
      }}
      onStartTask={(taskId) => {
        const task = availableTasks.find((item) => item.id === taskId)

        if (!task) return

        const guideGroup =
          taskId === 'home'
            ? homeGuideGroup
            : taskId === 'integration'
              ? integrationGuideGroup
              : undefined
        trackStepByStepTourEvent({
          action: 'task_started',
          task_id: taskId,
          permission_variant: getPermissionVariant(taskId),
        })

        if (taskId === 'knowledge' && !hasKnowledgeWalkthroughPermissions) {
          completeTask({
            taskId,
            onSuccess: (completedTaskIds) => trackTaskCompleted(completedTaskIds, taskId),
          })
          resetSession()
          setShellMode('expanded')
          return
        }

        const guides = getStepByStepTourGuides(taskId, guideGroup)
        const guideIndexes = createGuideIndexes(guides).filter((index) =>
          isGuideEligibleForPlan(guides[index]!, canSetPluginPreferences),
        )
        startTask({
          taskId,
          guideGroup,
          guideIndexes: guideIndexes.length > 0 ? guideIndexes : undefined,
        })
        router.push(task.route)
      }}
      onUncompleteTask={(taskId) => {
        uncompleteTask({
          taskId,
          onSuccess: (completedTaskIds) => {
            trackStepByStepTourEvent({
              action: 'task_reopened',
              task_id: taskId,
              completed_task_count: completedTaskIds.filter((completedTaskId) =>
                availableTaskIds.includes(completedTaskId),
              ).length,
            })
          },
        })
      }}
      className={cn(
        'transition-opacity duration-150 ease-out motion-reduce:transition-none',
        checklistExiting && 'opacity-0',
      )}
    />
  )

  return (
    <div className={cn('relative', className)}>
      {overlayVisible && !allTasksCompleted && activeTask && activeGuide && activeTargetElement && (
        <StepByStepTourCoachmark
          guide={{
            ...activeGuide,
            description: t(($) => $[activeGuide.description]),
            learnMoreHref: activeGuide.learnMoreDocPath
              ? docLink(activeGuide.learnMoreDocPath)
              : undefined,
            learnMoreLabel: t(($) => $[activeGuide.learnMoreLabel]),
            primaryActionLabel: t(($) => $[activeGuide.primaryActionLabel]),
            title: t(($) => $[activeGuide.title]),
          }}
          targetElement={activeTargetElement}
          placement={activeGuidePlacement}
          stepLabel={t(($) => $['stepByStepTour.stepLabel'], {
            current: activeStepIndex + 1,
            total: activeStepTotal,
          })}
          skipLabel={t(($) => $['stepByStepTour.skip'])}
          interactionPolicy={getStepByStepTourGuideInteractionPolicy(
            activeGuide,
            activeTask.canClickThrough,
          )}
          onSkip={skipActiveGuide}
          onComplete={completeActiveGuide}
        />
      )}
      {visible && (!allTasksCompleted || completionPromptVisible) && (
        <Popover open={overlayVisible && expanded}>
          <div
            ref={anchorRef}
            aria-hidden="true"
            className="pointer-events-none absolute bottom-0 left-0 h-0 w-full"
          />
          {checklistMinimized && floatingChecklist}
          {overlayVisible && (
            <PopoverContent
              placement="top-start"
              sideOffset={0}
              positionerProps={{
                anchor: anchorRef,
                collisionPadding: 8,
                collisionAvoidance: {
                  side: 'shift',
                  align: 'shift',
                  fallbackAxisSide: 'none',
                },
              }}
              popupClassName="overflow-visible rounded-none border-0 bg-transparent p-0 shadow-none"
            >
              {floatingChecklist}
            </PopoverContent>
          )}
        </Popover>
      )}
      {skipRecoveryVisible && (
        <SkipRecoveryPrompt
          label={t(($) => $['stepByStepTour.skipRecovery.label'])}
          message={t(($) => $['stepByStepTour.skipRecovery.message'])}
          dismissLabel={t(($) => $['stepByStepTour.skipRecovery.dismiss'])}
          onDismiss={() => setSkipRecoveryVisible(false)}
        />
      )}
    </div>
  )
}

function SkipRecoveryPrompt({
  dismissLabel,
  label,
  message,
  onDismiss,
}: {
  dismissLabel: string
  label: string
  message: string
  onDismiss: () => void
}) {
  const dismissRef = useRef<HTMLButtonElement>(null)

  useEffect(() => {
    dismissRef.current?.focus({ preventScroll: true })
  }, [])

  return (
    <section
      aria-label={label}
      className="fixed bottom-[76px] left-1.5 z-50 flex w-[260px] max-w-[calc(100vw-12px)] flex-col gap-1 rounded-2xl border-[0.5px] border-state-accent-hover-alt bg-state-accent-hover p-4 shadow-[0_20px_24px_-4px_var(--color-shadow-shadow-5),0_8px_8px_-4px_var(--color-shadow-shadow-1)] backdrop-blur-[10px]"
    >
      <p className="system-sm-regular text-text-secondary">{message}</p>
      <div className="flex h-12 items-end justify-end pt-4">
        <Button
          ref={dismissRef}
          variant="primary"
          size="medium"
          className="w-20"
          onClick={onDismiss}
        >
          {dismissLabel}
        </Button>
      </div>
      <span
        aria-hidden
        className="absolute top-full left-[214px] h-7 w-0.5 bg-state-accent-hover-alt"
      />
      <span
        aria-hidden
        className="absolute top-[calc(100%+22px)] left-[209px] size-3 rounded-full border-2 border-state-accent-hover bg-state-accent-solid shadow-xs"
      />
    </section>
  )
}
