'use client'

import {
  useCallback,
  useEffect,
  useEffectEvent,
  useMemo,
  useReducer,
  useRef,
  useState,
} from 'react'
import {
  Button,
  Calendar,
  ChipCombobox,
  type ComboboxOption,
  cn,
  Library,
  Popover,
  PopoverAnchor,
  PopoverContent,
  RefreshCw,
  toast,
} from '@sim/emcn'
import { Download, Workflow } from '@sim/emcn/icons'
import { formatDuration } from '@sim/utils/formatting'
import { useQueryClient } from '@tanstack/react-query'
import { useParams } from 'next/navigation'
import { useQueryState } from 'nuqs'
import type {
  WorkflowLogDetail,
  WorkflowLogRow,
  WorkflowLogSummary,
} from '@/lib/api/contracts/logs'
import { dollarsToCredits } from '@/lib/billing/credits/conversion'
import {
  getEndDateFromTimeRange,
  getStartDateFromTimeRange,
  hasActiveFilters,
} from '@/lib/logs/filters'
import { getTriggerOptions } from '@/lib/logs/get-trigger-options'
import { type ParsedFilter, parseQuery, queryToApiParams } from '@/lib/logs/query-parser'
import {
  type FolderData,
  SearchSuggestions,
  type TriggerData,
  type WorkflowData,
} from '@/lib/logs/search-suggestions'
import type {
  FilterTag,
  ResourceAction,
  ResourceColumn,
  ResourceRow,
  SearchConfig,
  SortConfig,
} from '@/app/workspace/[workspaceId]/components'
import { Resource, type ResourceTableHandle } from '@/app/workspace/[workspaceId]/components'
import { useLogFilters } from '@/app/workspace/[workspaceId]/logs/hooks/use-log-filters'
import { useSearchState } from '@/app/workspace/[workspaceId]/logs/hooks/use-search-state'
import {
  executionIdParam,
  logDetailsTabParam,
  logDetailsTabUrlKeys,
} from '@/app/workspace/[workspaceId]/logs/search-params'
import type { Suggestion } from '@/app/workspace/[workspaceId]/logs/types'
import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider'
import { getBlock } from '@/blocks/registry'
import { useFolderMap, useFolders } from '@/hooks/queries/folders'
import type { LogSortBy, LogSortOrder } from '@/hooks/queries/logs'
import {
  fetchLogDetail,
  logKeys,
  prefetchLogDetail,
  useCancelExecution,
  useDashboardStats,
  useLogByExecutionId,
  useLogDetail,
  useLogsList,
  useRetryExecution,
} from '@/hooks/queries/logs'
import { useWorkflowMap, useWorkflows } from '@/hooks/queries/workflows'
import { useDebounce } from '@/hooks/use-debounce'
import { useFilterStore } from '@/stores/logs/filters/store'
import { CORE_TRIGGER_TYPES } from '@/stores/logs/filters/types'
import { Dashboard, ExecutionSnapshot, LogDetails, LogRowContextMenu } from './components'
import {
  DELETED_WORKFLOW_LABEL,
  extractRetryInput,
  formatDate,
  formatDateShort,
  getDisplayStatus,
  type LogStatus,
  parseDuration,
  STATUS_CONFIG,
  StatusBadge,
  TriggerBadge,
} from './utils'

const LOGS_PER_PAGE = 50 as const
const SORTABLE_COLUMNS: readonly LogSortBy[] = ['date', 'duration', 'cost', 'status'] as const
const REFRESH_SPINNER_DURATION_MS = 1000 as const
const LIVE_REFRESH_INTERVAL_MS = 10_000 as const
const ACTIVE_RUN_DETAIL_REFRESH_MS = 3_000 as const

const LOG_COLUMNS: ResourceColumn[] = [
  { id: 'workflow', header: 'Workflow' },
  { id: 'date', header: 'Date' },
  { id: 'status', header: 'Status' },
  { id: 'cost', header: 'Cost' },
  { id: 'trigger', header: 'Trigger' },
  { id: 'duration', header: 'Duration' },
]

interface LogSelectionState {
  selectedLogId: string | null
  isSidebarOpen: boolean
}

type LogSelectionAction =
  | { type: 'TOGGLE_LOG'; logId: string }
  | { type: 'SELECT_LOG'; logId: string }
  | { type: 'CLOSE_SIDEBAR' }
  | { type: 'TOGGLE_SIDEBAR' }

function logSelectionReducer(
  state: LogSelectionState,
  action: LogSelectionAction
): LogSelectionState {
  switch (action.type) {
    case 'TOGGLE_LOG':
      if (state.selectedLogId === action.logId && state.isSidebarOpen) {
        return { selectedLogId: null, isSidebarOpen: false }
      }
      return { selectedLogId: action.logId, isSidebarOpen: true }
    case 'SELECT_LOG':
      return { ...state, selectedLogId: action.logId }
    case 'CLOSE_SIDEBAR':
      return { selectedLogId: null, isSidebarOpen: false }
    case 'TOGGLE_SIDEBAR':
      return state.selectedLogId ? { ...state, isSidebarOpen: !state.isSidebarOpen } : state
    default:
      return state
  }
}

const TIME_RANGE_OPTIONS: ComboboxOption[] = [
  { value: 'All time', label: 'All time' },
  { value: 'Past 30 minutes', label: 'Past 30 minutes' },
  { value: 'Past hour', label: 'Past hour' },
  { value: 'Past 6 hours', label: 'Past 6 hours' },
  { value: 'Past 12 hours', label: 'Past 12 hours' },
  { value: 'Past 24 hours', label: 'Past 24 hours' },
  { value: 'Past 3 days', label: 'Past 3 days' },
  { value: 'Past 7 days', label: 'Past 7 days' },
  { value: 'Past 14 days', label: 'Past 14 days' },
  { value: 'Past 30 days', label: 'Past 30 days' },
  { value: 'Custom range', label: 'Custom range' },
] as const

const colorIconCache = new Map<string, React.ComponentType<{ className?: string }>>()

function getColorIcon(color: string): React.ComponentType<{ className?: string }> {
  const cached = colorIconCache.get(color)
  if (cached) return cached

  const ColorIcon = ({ className }: { className?: string }) => (
    <div
      className={cn(className, 'flex-shrink-0 rounded-[3px]')}
      style={{
        backgroundColor: color,
        width: 10,
        height: 10,
      }}
    />
  )
  ColorIcon.displayName = `ColorIcon(${color})`
  colorIconCache.set(color, ColorIcon)
  return ColorIcon
}

function WorkflowOptionIcon({ className }: { className?: string }) {
  return <Workflow className={cn(className, 'flex-shrink-0 text-[var(--text-icon)]')} />
}

function getTriggerIcon(
  triggerType: string
): React.ComponentType<{ className?: string }> | undefined {
  if ((CORE_TRIGGER_TYPES as readonly string[]).includes(triggerType)) return undefined
  const block = getBlock(triggerType)
  if (!block?.icon) return undefined
  const BlockIcon = block.icon
  const TriggerIcon = ({ className }: { className?: string }) => (
    <BlockIcon className={cn(className, 'flex-shrink-0')} style={{ width: 12, height: 12 }} />
  )
  TriggerIcon.displayName = `TriggerIcon(${triggerType})`
  return TriggerIcon
}

function SpinningRefreshCw(props: React.SVGProps<SVGSVGElement>) {
  return <RefreshCw {...props} animate />
}

/**
 * Logs page component displaying workflow execution history.
 * Supports filtering, search, live updates, and detailed log inspection.
 * @returns The logs page view with table and sidebar details
 */
export default function Logs() {
  const params = useParams()
  const workspaceId = params.workspaceId as string

  const {
    timeRange,
    startDate,
    endDate,
    level,
    workflowIds,
    folderIds,
    setWorkflowIds,
    searchQuery: urlSearchQuery,
    setSearchQuery: setUrlSearchQuery,
    triggers,
    resetFilters,
    setLevel,
    setFolderIds,
    setTriggers,
    setTimeRange,
    setDateRange,
    clearDateRange,
  } = useLogFilters()

  const viewMode = useFilterStore((s) => s.viewMode)
  const setViewMode = useFilterStore((s) => s.setViewMode)

  const [{ selectedLogId, isSidebarOpen }, dispatch] = useReducer(logSelectionReducer, {
    selectedLogId: null,
    isSidebarOpen: false,
  })

  const [executionId] = useQueryState(executionIdParam.key, executionIdParam.parser)
  const [pendingExecutionId, setPendingExecutionId] = useState<string | null>(() => executionId)

  /**
   * The log-details `tab` param is owned/written by the details panel, but the
   * orchestrator must clear it when the panel closes so a lingering `?tab=trace`
   * never carries over to the next log opened from the list.
   */
  const [, setLogDetailsTab] = useQueryState(logDetailsTabParam.key, {
    ...logDetailsTabParam.parser,
    ...logDetailsTabUrlKeys,
  })

  /**
   * `urlSearchQuery` is the instant nuqs value (its URL write is debounced inside
   * `useLogFilters`); the query/filtering still debounce off it to avoid
   * per-keystroke fetches.
   */
  const debouncedSearchQuery = useDebounce(urlSearchQuery, 300)

  const isLive = true
  const [isVisuallyRefreshing, setIsVisuallyRefreshing] = useState(false)
  const [isExporting, setIsExporting] = useState(false)
  const refreshTimersRef = useRef(new Set<number>())
  const logsRef = useRef<WorkflowLogSummary[]>([])
  const selectedLogIndexRef = useRef(-1)
  const selectedLogIdRef = useRef<string | null>(null)
  const shouldScrollIntoViewRef = useRef(false)
  const resourceTableRef = useRef<ResourceTableHandle>(null)
  const logsRefetchRef = useRef<() => void>(() => {})
  const activeLogRefetchRef = useRef<() => void>(() => {})
  const activeLogTabRef = useRef<string>('overview')
  const logsQueryRef = useRef({ isFetching: false, hasNextPage: false, fetchNextPage: () => {} })
  const [activeSort, setActiveSort] = useState<{
    column: string
    direction: 'asc' | 'desc'
  } | null>(null)
  const userPermissions = useUserPermissionsContext()

  const [contextMenuOpen, setContextMenuOpen] = useState(false)
  const [contextMenuPosition, setContextMenuPosition] = useState({ x: 0, y: 0 })
  const [contextMenuLog, setContextMenuLog] = useState<WorkflowLogSummary | null>(null)

  const [previewLogId, setPreviewLogId] = useState<string | null>(null)

  const queryClient = useQueryClient()

  const refetchInterval = useCallback(
    (query: { state: { data?: WorkflowLogDetail } }) => {
      if (!isLive) return false
      const status = query.state.data?.status
      return status === 'running' || status === 'pending' ? ACTIVE_RUN_DETAIL_REFRESH_MS : false
    },
    [isLive]
  )

  const selectedDetailQuery = useLogDetail(selectedLogId ?? undefined, workspaceId, {
    refetchInterval,
  })

  const previewDetailQuery = useLogDetail(previewLogId ?? undefined, workspaceId, {
    refetchInterval,
  })

  const sortBy: LogSortBy =
    activeSort && SORTABLE_COLUMNS.includes(activeSort.column as LogSortBy)
      ? (activeSort.column as LogSortBy)
      : 'date'
  const sortOrder: LogSortOrder = activeSort?.direction ?? 'desc'

  const logFilters = useMemo(
    () => ({
      timeRange,
      startDate,
      endDate,
      level,
      workflowIds,
      folderIds,
      triggers,
      searchQuery: debouncedSearchQuery,
      limit: LOGS_PER_PAGE,
      sortBy,
      sortOrder,
    }),
    [
      timeRange,
      startDate,
      endDate,
      level,
      workflowIds,
      folderIds,
      triggers,
      debouncedSearchQuery,
      sortBy,
      sortOrder,
    ]
  )

  const logsQuery = useLogsList(workspaceId, logFilters, {
    refetchInterval: isLive ? LIVE_REFRESH_INTERVAL_MS : false,
  })

  const dashboardFilters = useMemo(
    () => ({
      timeRange,
      startDate,
      endDate,
      level,
      workflowIds,
      folderIds,
      triggers,
      searchQuery: debouncedSearchQuery,
    }),
    [timeRange, startDate, endDate, level, workflowIds, folderIds, triggers, debouncedSearchQuery]
  )

  const dashboardStatsQuery = useDashboardStats(workspaceId, dashboardFilters, {
    refetchInterval: isLive ? LIVE_REFRESH_INTERVAL_MS : false,
  })

  const logs = useMemo(() => {
    return logsQuery.data?.pages?.flatMap((page) => page.logs) ?? []
  }, [logsQuery.data?.pages])

  const selectedLogIndex = selectedLogId ? logs.findIndex((l) => l.id === selectedLogId) : -1
  const selectedLogFromList = selectedLogIndex >= 0 ? logs[selectedLogIndex] : null
  const selectedLog = selectedDetailQuery.data ?? selectedLogFromList ?? null

  const handleLogHover = useCallback(
    (rowId: string) => {
      prefetchLogDetail(queryClient, rowId, workspaceId)
    },
    [queryClient, workspaceId]
  )

  useFolders(workspaceId)

  logsRef.current = logs
  selectedLogIndexRef.current = selectedLogIndex
  selectedLogIdRef.current = selectedLogId
  logsRefetchRef.current = logsQuery.refetch
  activeLogRefetchRef.current = selectedDetailQuery.refetch
  logsQueryRef.current = {
    isFetching: logsQuery.isFetching,
    hasNextPage: logsQuery.hasNextPage ?? false,
    fetchNextPage: logsQuery.fetchNextPage,
  }

  const deepLinkQuery = useLogByExecutionId(workspaceId, pendingExecutionId)

  useEffect(() => {
    if (!pendingExecutionId) return
    const resolvedId = deepLinkQuery.data?.id
    if (resolvedId) {
      dispatch({ type: 'TOGGLE_LOG', logId: resolvedId })
      setPendingExecutionId(null)
    } else if (deepLinkQuery.isError) {
      setPendingExecutionId(null)
    }
  }, [pendingExecutionId, deepLinkQuery.data, deepLinkQuery.isError])

  useEffect(() => {
    const timers = refreshTimersRef.current
    return () => {
      timers.forEach((id) => window.clearTimeout(id))
      timers.clear()
    }
  }, [])

  const handleLogClick = useCallback((rowId: string) => {
    dispatch({ type: 'TOGGLE_LOG', logId: rowId })
  }, [])

  const handleNavigateNext = useCallback(() => {
    const idx = selectedLogIndexRef.current
    const currentLogs = logsRef.current
    if (idx >= 0 && idx < currentLogs.length - 1) {
      shouldScrollIntoViewRef.current = true
      dispatch({ type: 'SELECT_LOG', logId: currentLogs[idx + 1].id })
    }
  }, [])

  const handleNavigatePrev = useCallback(() => {
    const idx = selectedLogIndexRef.current
    if (idx > 0) {
      shouldScrollIntoViewRef.current = true
      dispatch({ type: 'SELECT_LOG', logId: logsRef.current[idx - 1].id })
    }
  }, [])

  const handleCloseSidebar = useCallback(() => {
    dispatch({ type: 'CLOSE_SIDEBAR' })
    activeLogTabRef.current = 'overview'
  }, [])

  /**
   * Strip the `tab` param whenever the detail panel transitions from open to
   * closed — by the X button, toggling the same row, or the keyboard — so
   * reopening another log starts on overview rather than inheriting the closed
   * log's tab. Guarded on a prior-open ref so an initial deep-linked `?tab=` is
   * preserved (the panel isn't open yet on first mount).
   */
  const wasSidebarOpenRef = useRef(false)
  useEffect(() => {
    if (isSidebarOpen) {
      wasSidebarOpenRef.current = true
    } else if (wasSidebarOpenRef.current) {
      wasSidebarOpenRef.current = false
      setLogDetailsTab(null)
    }
  }, [isSidebarOpen, setLogDetailsTab])

  const handleActiveTabChange = useCallback((tab: string) => {
    activeLogTabRef.current = tab
  }, [])

  const handleLogContextMenu = useCallback(
    (e: React.MouseEvent, rowId: string) => {
      e.preventDefault()
      const log = logs.find((l) => l.id === rowId) ?? null
      setContextMenuPosition({ x: e.clientX, y: e.clientY })
      setContextMenuLog(log)
      setContextMenuOpen(true)
    },
    [logs]
  )

  const handleCopyExecutionId = useCallback(() => {
    if (contextMenuLog?.executionId) {
      navigator.clipboard.writeText(contextMenuLog.executionId).catch(() => {})
    }
  }, [contextMenuLog])

  const handleCopyLink = useCallback(() => {
    if (contextMenuLog?.executionId) {
      const url = `${window.location.origin}/workspace/${workspaceId}/logs?executionId=${contextMenuLog.executionId}`
      navigator.clipboard.writeText(url).catch(() => {})
    }
  }, [contextMenuLog, workspaceId])

  const handleOpenWorkflow = useCallback(() => {
    const wfId = contextMenuLog?.workflow?.id || contextMenuLog?.workflowId
    if (wfId) {
      window.open(`/workspace/${workspaceId}/w/${wfId}`, '_blank')
    }
  }, [contextMenuLog, workspaceId])

  const handleToggleWorkflowFilter = useCallback(() => {
    const wfId = contextMenuLog?.workflow?.id || contextMenuLog?.workflowId
    if (!wfId) return

    if (workflowIds.length === 1 && workflowIds[0] === wfId) {
      setWorkflowIds([])
    } else {
      setWorkflowIds([wfId])
    }
  }, [contextMenuLog, workflowIds, setWorkflowIds])

  /**
   * `resetFilters()` already clears `search` (sets it to null), so no separate
   * search reset is needed here.
   */
  const handleClearAllFilters = useCallback(() => {
    resetFilters()
  }, [resetFilters])

  const handleOpenPreview = useCallback(() => {
    if (contextMenuLog?.id) {
      setPreviewLogId(contextMenuLog.id)
    }
  }, [contextMenuLog])

  const cancelExecution = useCancelExecution(workspaceId)
  const retryExecution = useRetryExecution()

  const handleCancelExecution = useCallback(() => {
    const workflowId = contextMenuLog?.workflow?.id || contextMenuLog?.workflowId
    const executionId = contextMenuLog?.executionId
    if (workflowId && executionId) {
      cancelExecution.mutate({ workflowId, executionId })
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [contextMenuLog])

  const retryLog = useCallback(
    async (log: WorkflowLogRow | null) => {
      const workflowId = log?.workflow?.id || log?.workflowId
      const logId = log?.id
      if (!workflowId || !logId) return

      try {
        const detailLog = await queryClient.fetchQuery({
          queryKey: logKeys.detail(workspaceId, logId),
          queryFn: ({ signal }) => fetchLogDetail(logId, workspaceId, signal),
          staleTime: 30 * 1000,
        })
        const input = extractRetryInput(detailLog)
        await retryExecution.mutateAsync({ workflowId, input })
        toast.success('Retry started')
      } catch {
        toast.error('Failed to retry execution')
      }
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps
    []
  )

  const handleRetryExecution = useCallback(() => {
    retryLog(contextMenuLog)
  }, [contextMenuLog, retryLog])

  const handleRetrySidebarExecution = useCallback(() => {
    retryLog(selectedLog)
  }, [selectedLog, retryLog])

  const contextMenuWorkflowId = contextMenuLog?.workflow?.id || contextMenuLog?.workflowId
  const isFilteredByThisWorkflow = Boolean(
    contextMenuWorkflowId && workflowIds.length === 1 && workflowIds[0] === contextMenuWorkflowId
  )

  const filtersActive = hasActiveFilters({
    timeRange,
    level,
    workflowIds,
    folderIds,
    triggers,
    searchQuery: debouncedSearchQuery,
  })

  useEffect(() => {
    if (!selectedLogId || !shouldScrollIntoViewRef.current) return
    shouldScrollIntoViewRef.current = false
    // Route through the virtualizer; a querySelector would miss windowed-out rows.
    resourceTableRef.current?.scrollToRow(selectedLogId)
  }, [selectedLogId, selectedLogIndex])

  const effectiveSidebarOpen =
    isSidebarOpen && (selectedLogIndex !== -1 || !!selectedDetailQuery.data)

  const triggerVisualRefresh = useCallback(() => {
    setIsVisuallyRefreshing(true)
    const timerId = window.setTimeout(() => {
      setIsVisuallyRefreshing(false)
      refreshTimersRef.current.delete(timerId)
    }, REFRESH_SPINNER_DURATION_MS)
    refreshTimersRef.current.add(timerId)
  }, [])

  const handleRefresh = useCallback(() => {
    triggerVisualRefresh()
    logsRefetchRef.current()
    if (selectedLogIdRef.current) {
      activeLogRefetchRef.current()
    }
  }, [triggerVisualRefresh])

  const prevIsFetchingRef = useRef(logsQuery.isFetching)
  useEffect(() => {
    const wasFetching = prevIsFetchingRef.current
    const isFetching = logsQuery.isFetching
    prevIsFetchingRef.current = isFetching

    if (isLive && !wasFetching && isFetching) {
      triggerVisualRefresh()
    }
  }, [logsQuery.isFetching, isLive, triggerVisualRefresh])

  const handleExport = useCallback(async () => {
    setIsExporting(true)
    try {
      const params = new URLSearchParams()
      params.set('workspaceId', workspaceId)
      if (level !== 'all') params.set('level', level)
      if (triggers.length > 0) params.set('triggers', triggers.join(','))
      if (workflowIds.length > 0) params.set('workflowIds', workflowIds.join(','))
      if (folderIds.length > 0) params.set('folderIds', folderIds.join(','))

      const computedStartDate = getStartDateFromTimeRange(timeRange, startDate)
      if (computedStartDate) {
        params.set('startDate', computedStartDate.toISOString())
      }

      const computedEndDate = getEndDateFromTimeRange(timeRange, endDate)
      if (computedEndDate) {
        params.set('endDate', computedEndDate.toISOString())
      }

      const parsed = parseQuery(debouncedSearchQuery)
      const extra = queryToApiParams(parsed)
      Object.entries(extra).forEach(([k, v]) => params.set(k, v))

      const url = `/api/logs/export?${params.toString()}`
      const a = document.createElement('a')
      a.href = url
      a.download = 'logs_export.csv'
      document.body.appendChild(a)
      a.click()
      a.remove()
    } finally {
      setIsExporting(false)
    }
  }, [
    workspaceId,
    level,
    triggers,
    workflowIds,
    folderIds,
    timeRange,
    startDate,
    endDate,
    debouncedSearchQuery,
  ])

  const loadMoreLogs = useCallback(() => {
    const { isFetching, hasNextPage, fetchNextPage } = logsQueryRef.current
    if (!isFetching && hasNextPage) {
      fetchNextPage()
    }
  }, [])

  const handleNavigateNextEvent = useEffectEvent(handleNavigateNext)
  const handleNavigatePrevEvent = useEffectEvent(handleNavigatePrev)

  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      const tag = (e.target as HTMLElement)?.tagName
      if (tag === 'INPUT' || tag === 'TEXTAREA') return
      if (activeLogTabRef.current === 'trace') return
      const currentLogs = logsRef.current
      const currentIndex = selectedLogIndexRef.current
      if (currentLogs.length === 0) return

      if (currentIndex === -1 && (e.key === 'ArrowUp' || e.key === 'ArrowDown')) {
        e.preventDefault()
        shouldScrollIntoViewRef.current = true
        dispatch({ type: 'SELECT_LOG', logId: currentLogs[0].id })
        return
      }

      if (e.key === 'ArrowUp' && !e.metaKey && !e.ctrlKey && currentIndex > 0) {
        e.preventDefault()
        handleNavigatePrevEvent()
      }

      if (
        e.key === 'ArrowDown' &&
        !e.metaKey &&
        !e.ctrlKey &&
        currentIndex < currentLogs.length - 1
      ) {
        e.preventDefault()
        handleNavigateNextEvent()
      }

      if (e.key === 'Enter' && selectedLogIdRef.current) {
        e.preventDefault()
        dispatch({ type: 'TOGGLE_SIDEBAR' })
      }
    }

    window.addEventListener('keydown', handleKeyDown)
    return () => window.removeEventListener('keydown', handleKeyDown)
  }, [])

  const handleCloseContextMenu = useCallback(() => setContextMenuOpen(false), [])
  function handleClosePreview() {
    setPreviewLogId(null)
  }

  const isDashboardView = viewMode === 'dashboard'

  const rows: ResourceRow[] = useMemo(
    () =>
      logs.map((log) => {
        const formattedDate = formatDate(log.createdAt)
        const displayStatus = getDisplayStatus(log.status)
        const isMothershipJob = log.trigger === 'mothership'
        const isDeletedWorkflow = !isMothershipJob && !log.workflow?.id && !log.workflowId
        const workflowName = isMothershipJob
          ? log.jobTitle || 'Untitled Job'
          : isDeletedWorkflow
            ? DELETED_WORKFLOW_LABEL
            : log.workflow?.name || 'Unknown'

        const durationMs = parseDuration({ duration: log.duration ?? undefined })
        const durationText =
          durationMs != null ? (formatDuration(durationMs, { precision: 2 }) ?? '—') : '—'

        const costCredits =
          typeof log.cost?.total === 'number' ? dollarsToCredits(log.cost.total) : null
        const costText =
          costCredits !== null
            ? `${costCredits.toLocaleString()} ${costCredits === 1 ? 'credit' : 'credits'}`
            : '—'

        return {
          id: log.id,
          cells: {
            workflow: {
              label: workflowName,
            },
            date: { label: `${formattedDate.compactDate} ${formattedDate.compactTime}` },
            status: { content: <StatusBadge status={displayStatus} /> },
            cost: { label: costText },
            trigger: { content: <TriggerBadge trigger={log.trigger || 'manual'} /> },
            duration: { label: durationText },
          },
        }
      }),
    [logs]
  )

  const sidebarOverlay = (
    <LogDetails
      log={selectedLog}
      isOpen={effectiveSidebarOpen}
      onClose={handleCloseSidebar}
      onNavigateNext={handleNavigateNext}
      onNavigatePrev={handleNavigatePrev}
      hasNext={selectedLogIndex >= 0 && selectedLogIndex < logs.length - 1}
      hasPrev={selectedLogIndex > 0}
      onRetryExecution={handleRetrySidebarExecution}
      isRetryPending={retryExecution.isPending}
      onActiveTabChange={handleActiveTabChange}
    />
  )

  const { data: allWorkflows = {} } = useWorkflowMap(workspaceId)
  const { data: folders = {} } = useFolderMap(workspaceId)

  const filterTags = useMemo<FilterTag[]>(() => {
    const tags: FilterTag[] = []

    if (level && level !== 'all') {
      const statuses = level.split(',').filter(Boolean)
      const labels = statuses.map((s) => STATUS_CONFIG[s as LogStatus]?.label ?? s)
      tags.push({
        label: `Status: ${labels.join(', ')}`,
        onRemove: () => setLevel('all'),
      })
    }

    if (workflowIds.length > 0) {
      const names = workflowIds.map((id) => allWorkflows[id]?.name ?? id.slice(0, 8))
      tags.push({
        label: `Workflow: ${names.join(', ')}`,
        onRemove: () => setWorkflowIds([]),
      })
    }

    if (folderIds.length > 0) {
      const names = folderIds.map((id) => folders[id]?.name ?? id.slice(0, 8))
      tags.push({
        label: `Folder: ${names.join(', ')}`,
        onRemove: () => setFolderIds([]),
      })
    }

    if (triggers.length > 0) {
      tags.push({
        label: `Trigger: ${triggers.join(', ')}`,
        onRemove: () => setTriggers([]),
      })
    }

    if (timeRange !== 'All time') {
      tags.push({
        label:
          timeRange === 'Custom range' && startDate && endDate
            ? `${formatDateShort(startDate)} – ${formatDateShort(endDate)}`
            : timeRange,
        onRemove: () => {
          clearDateRange()
          setTimeRange('All time')
        },
      })
    }

    return tags
  }, [
    level,
    setLevel,
    workflowIds,
    setWorkflowIds,
    allWorkflows,
    folderIds,
    setFolderIds,
    folders,
    triggers,
    setTriggers,
    timeRange,
    startDate,
    endDate,
    clearDateRange,
    setTimeRange,
  ])

  const workflowsData = useMemo<WorkflowData[]>(
    () =>
      Object.values(allWorkflows).map((w) => ({
        id: w.id,
        name: w.name,
        description: w.description,
      })),
    [allWorkflows]
  )
  const foldersData = useMemo<FolderData[]>(
    () => Object.values(folders).map((f) => ({ id: f.id, name: f.name })),
    [folders]
  )
  const triggersData = useMemo<TriggerData[]>(
    () => getTriggerOptions().map((t) => ({ value: t.value, label: t.label, color: t.color })),
    []
  )
  const suggestionEngine = useMemo(
    () => new SearchSuggestions(workflowsData, foldersData, triggersData),
    [workflowsData, foldersData, triggersData]
  )

  const handleFiltersChange = useCallback(
    (filters: ParsedFilter[], textSearch: string) => {
      const filterStrings = filters.map(
        (f) => `${f.field}:${f.operator !== '=' ? f.operator : ''}${f.originalValue}`
      )
      const fullQuery = [...filterStrings, textSearch].filter(Boolean).join(' ')
      setUrlSearchQuery(fullQuery)
    },
    [setUrlSearchQuery]
  )

  const getSuggestions = useCallback(
    (input: string) => suggestionEngine.getSuggestions(input),
    [suggestionEngine]
  )

  const {
    appliedFilters,
    currentInput,
    textSearch,
    isOpen: isSuggestionsOpen,
    suggestions,
    sections,
    highlightedIndex,
    highlightedBadgeIndex,
    inputRef: searchInputRef,
    dropdownRef: searchDropdownRef,
    handleInputChange: handleSearchInputChange,
    handleSuggestionSelect,
    handleKeyDown: handleSearchKeyDown,
    handleFocus: handleSearchFocus,
    handleBlur: handleSearchBlur,
    removeBadge,
    clearAll: clearSearch,
    setHighlightedIndex,
    initializeFromQuery,
  } = useSearchState({
    onFiltersChange: handleFiltersChange,
    getSuggestions,
  })

  const lastExternalSearchValue = useRef<string | undefined>(undefined)
  useEffect(() => {
    if (urlSearchQuery === lastExternalSearchValue.current) return
    const isMount = lastExternalSearchValue.current === undefined
    lastExternalSearchValue.current = urlSearchQuery
    // On mount with no initial query, skip the no-op parse
    if (isMount && !urlSearchQuery) return
    const parsed = parseQuery(urlSearchQuery)
    initializeFromQuery(parsed.textSearch, parsed.filters)
  }, [urlSearchQuery, initializeFromQuery])

  useEffect(() => {
    if (!isSuggestionsOpen || highlightedIndex < 0) return
    const container = searchDropdownRef.current
    const el = container?.querySelector(`[data-index="${highlightedIndex}"]`)
    if (container && el) {
      el.scrollIntoView({ block: 'nearest', behavior: 'smooth' })
    }
  }, [isSuggestionsOpen, highlightedIndex])

  const suggestionsDropdown = useMemo(() => {
    if (!isSuggestionsOpen || suggestions.length === 0) return undefined
    const suggestionType =
      sections.length > 0 ? 'multi-section' : (suggestions[0]?.category ?? null)

    return (
      <div className='max-h-96 overflow-y-auto px-1'>
        {sections.length > 0 ? (
          <div className='py-1'>
            {suggestions[0]?.category === 'show-all' && (
              <SuggestionButton
                suggestion={suggestions[0]}
                index={0}
                highlighted={highlightedIndex === 0}
                onHover={setHighlightedIndex}
                onSelect={handleSuggestionSelect}
              />
            )}
            {sections.map((section) => (
              <div key={section.title}>
                <div className='px-3 py-1.5 font-medium text-[var(--text-tertiary)] text-caption uppercase tracking-wide'>
                  {section.title}
                </div>
                {section.suggestions.map((suggestion) => {
                  if (suggestion.category === 'show-all') return null
                  const index = suggestions.indexOf(suggestion)
                  return (
                    <SuggestionButton
                      key={suggestion.id}
                      suggestion={suggestion}
                      index={index}
                      highlighted={index === highlightedIndex}
                      onHover={setHighlightedIndex}
                      onSelect={handleSuggestionSelect}
                      showCategory
                    />
                  )
                })}
              </div>
            ))}
          </div>
        ) : (
          <div className='py-1'>
            {suggestionType === 'filters' && (
              <div className='px-3 py-1.5 font-medium text-[var(--text-tertiary)] text-caption uppercase tracking-wide'>
                SUGGESTED FILTERS
              </div>
            )}
            {suggestions.map((suggestion, index) => (
              <SuggestionButton
                key={suggestion.id}
                suggestion={suggestion}
                index={index}
                highlighted={index === highlightedIndex}
                onHover={setHighlightedIndex}
                onSelect={handleSuggestionSelect}
              />
            ))}
          </div>
        )}
      </div>
    )
  }, [
    isSuggestionsOpen,
    suggestions,
    sections,
    highlightedIndex,
    setHighlightedIndex,
    handleSuggestionSelect,
  ])

  const searchTags = useMemo(
    () => [
      ...appliedFilters.map((f, i) => ({
        label: f.field,
        value: `${f.operator !== '=' ? f.operator : ''}${f.originalValue}`,
        onRemove: () => removeBadge(i),
      })),
      ...(textSearch
        ? [
            {
              label: 'search',
              value: textSearch,
              onRemove: () => handleFiltersChange(appliedFilters, ''),
            },
          ]
        : []),
    ],
    [appliedFilters, textSearch, removeBadge, handleFiltersChange]
  )

  const sortConfig = useMemo<SortConfig>(
    () => ({
      options: [
        { id: 'date', label: 'Date' },
        { id: 'duration', label: 'Duration' },
        { id: 'cost', label: 'Cost' },
        { id: 'status', label: 'Status' },
      ],
      active: activeSort,
      onSort: (column, direction) => setActiveSort({ column, direction }),
      onClear: () => setActiveSort(null),
    }),
    [activeSort]
  )

  const searchConfig = useMemo<SearchConfig>(
    () => ({
      value: currentInput,
      onChange: handleSearchInputChange,
      placeholder: 'Search logs...',
      inputRef: searchInputRef,
      onKeyDown: handleSearchKeyDown,
      onFocus: handleSearchFocus,
      onBlur: handleSearchBlur,
      tags: searchTags.length > 0 ? searchTags : undefined,
      highlightedTagIndex: highlightedBadgeIndex,
      onClearAll: clearSearch,
      dropdown: suggestionsDropdown,
      dropdownRef: searchDropdownRef,
    }),
    [
      currentInput,
      handleSearchInputChange,
      searchInputRef,
      handleSearchKeyDown,
      handleSearchFocus,
      handleSearchBlur,
      searchTags,
      highlightedBadgeIndex,
      clearSearch,
      suggestionsDropdown,
      searchDropdownRef,
    ]
  )

  const refreshIcon = isVisuallyRefreshing ? SpinningRefreshCw : RefreshCw

  const headerActions = useMemo<ResourceAction[]>(
    () => [
      {
        text: 'Export',
        icon: Download,
        onSelect: handleExport,
        disabled: !userPermissions.canEdit || isExporting || logs.length === 0,
      },
      {
        text: 'Refresh',
        icon: refreshIcon,
        onSelect: handleRefresh,
        disabled: isVisuallyRefreshing,
      },
      {
        text: 'Logs',
        onSelect: () => setViewMode('logs'),
        active: !isDashboardView,
      },
      {
        text: 'Dashboard',
        onSelect: () => setViewMode('dashboard'),
        active: isDashboardView,
      },
    ],
    [
      isDashboardView,
      setViewMode,
      refreshIcon,
      isVisuallyRefreshing,
      handleRefresh,
      handleExport,
      userPermissions.canEdit,
      isExporting,
      logs.length,
    ]
  )

  return (
    <>
      <Resource>
        <Resource.Header icon={Library} title='Logs' actions={headerActions} />
        <Resource.Options
          search={searchConfig}
          sort={sortConfig}
          filter={{
            content: (
              <LogsFilterPanel
                searchQuery={urlSearchQuery}
                onSearchQueryChange={setUrlSearchQuery}
              />
            ),
          }}
          filterTags={filterTags}
        />
        {isDashboardView ? (
          <div className='relative flex min-h-0 flex-1 flex-col overflow-auto'>
            <div className='flex min-h-0 flex-1 flex-col px-6'>
              <Dashboard
                stats={dashboardStatsQuery.data}
                isLoading={dashboardStatsQuery.isLoading}
                error={dashboardStatsQuery.error}
                searchQuery={debouncedSearchQuery}
              />
            </div>
            {sidebarOverlay}
          </div>
        ) : (
          <Resource.Table
            apiRef={resourceTableRef}
            virtualized
            columns={LOG_COLUMNS}
            rows={rows}
            selectedRowId={selectedLogId}
            onRowClick={handleLogClick}
            onRowHover={handleLogHover}
            onRowContextMenu={handleLogContextMenu}
            onLoadMore={loadMoreLogs}
            hasMore={logsQuery.hasNextPage ?? false}
            isLoadingMore={logsQuery.isFetchingNextPage}
            overlay={sidebarOverlay}
          />
        )}
      </Resource>

      <LogRowContextMenu
        isOpen={contextMenuOpen}
        position={contextMenuPosition}
        onClose={handleCloseContextMenu}
        log={contextMenuLog}
        onCopyExecutionId={handleCopyExecutionId}
        onCopyLink={handleCopyLink}
        onOpenWorkflow={handleOpenWorkflow}
        onOpenPreview={handleOpenPreview}
        onCancelExecution={handleCancelExecution}
        onRetryExecution={handleRetryExecution}
        isRetryPending={retryExecution.isPending}
        onToggleWorkflowFilter={handleToggleWorkflowFilter}
        onClearAllFilters={handleClearAllFilters}
        isFilteredByThisWorkflow={isFilteredByThisWorkflow}
        hasActiveFilters={filtersActive}
      />

      {previewLogId !== null && previewDetailQuery.data?.executionId && (
        <ExecutionSnapshot
          executionId={previewDetailQuery.data.executionId}
          traceSpans={previewDetailQuery.data.executionData?.traceSpans}
          isModal
          isOpen={previewLogId !== null}
          onClose={handleClosePreview}
        />
      )}
    </>
  )
}

interface LogsFilterPanelProps {
  searchQuery: string
  onSearchQueryChange: (query: string) => void
}

function LogsFilterPanel({ searchQuery, onSearchQueryChange }: LogsFilterPanelProps) {
  const params = useParams()
  const workspaceId = params.workspaceId as string

  const {
    level,
    setLevel,
    workflowIds,
    setWorkflowIds,
    folderIds,
    setFolderIds,
    triggers,
    setTriggers,
    timeRange,
    setTimeRange,
    startDate,
    endDate,
    setDateRange,
    clearDateRange,
    resetFilters,
  } = useLogFilters()

  const [datePickerOpen, setDatePickerOpen] = useState(false)
  const previousTimeRangeRef = useRef(timeRange)
  const dateRangeAppliedRef = useRef(false)
  const { data: folders = {} } = useFolderMap(workspaceId)
  const { data: allWorkflowList = [] } = useWorkflows(workspaceId)

  const workflows = allWorkflowList.map((w) => ({ id: w.id, name: w.name }))
  const folderList = Object.values(folders).filter((f) => f.workspaceId === workspaceId)

  const selectedStatuses = level === 'all' || !level ? [] : level.split(',').filter(Boolean)

  const statusOptions: ComboboxOption[] = useMemo(
    () =>
      (Object.keys(STATUS_CONFIG) as LogStatus[])
        .filter((status) => STATUS_CONFIG[status].filterable)
        .map((status) => ({
          value: status,
          label: STATUS_CONFIG[status].label,
          icon: getColorIcon(STATUS_CONFIG[status].color),
        })),
    []
  )

  const handleStatusChange = (values: string[]) => {
    setLevel(values.length === 0 ? 'all' : values.join(','))
  }

  const statusDisplayLabel =
    selectedStatuses.length === 0
      ? 'Status'
      : selectedStatuses.length === 1
        ? statusOptions.find((s) => s.value === selectedStatuses[0])?.label || '1 selected'
        : `${selectedStatuses.length} selected`

  const selectedStatusColor =
    selectedStatuses.length === 1
      ? (STATUS_CONFIG[selectedStatuses[0] as LogStatus]?.color ?? null)
      : null

  const workflowOptions: ComboboxOption[] = workflows.map((w) => ({
    value: w.id,
    label: w.name,
    icon: WorkflowOptionIcon,
  }))

  const workflowDisplayLabel =
    workflowIds.length === 0
      ? 'Workflow'
      : workflowIds.length === 1
        ? workflows.find((w) => w.id === workflowIds[0])?.name || '1 selected'
        : `${workflowIds.length} workflows`

  const selectedWorkflow =
    workflowIds.length === 1 ? workflows.find((w) => w.id === workflowIds[0]) : null

  const folderOptions: ComboboxOption[] = folderList.map((f) => ({ value: f.id, label: f.name }))

  const folderDisplayLabel =
    folderIds.length === 0
      ? 'Folder'
      : folderIds.length === 1
        ? folderList.find((f) => f.id === folderIds[0])?.name || '1 selected'
        : `${folderIds.length} folders`

  const triggerOptions: ComboboxOption[] = useMemo(
    () =>
      getTriggerOptions().map((t) => ({
        value: t.value,
        label: t.label,
        icon: getTriggerIcon(t.value),
      })),
    []
  )

  const triggerDisplayLabel =
    triggers.length === 0
      ? 'Trigger'
      : triggers.length === 1
        ? triggerOptions.find((t) => t.value === triggers[0])?.label || '1 selected'
        : `${triggers.length} triggers`

  const timeDisplayLabel =
    timeRange === 'All time'
      ? 'Time'
      : timeRange === 'Custom range' && startDate && endDate
        ? `${formatDateShort(startDate)} - ${formatDateShort(endDate)}`
        : timeRange === 'Custom range'
          ? 'Custom range'
          : timeRange

  const handleTimeRangeChange = (val: string) => {
    if (val === 'Custom range') {
      previousTimeRangeRef.current = timeRange
      setDatePickerOpen(true)
    } else {
      clearDateRange()
      setTimeRange(val as typeof timeRange)
    }
  }

  const handleDateRangeApply = (start: string, end: string) => {
    dateRangeAppliedRef.current = true
    setDateRange(start, end)
    setDatePickerOpen(false)
  }

  const handleDatePickerCancel = () => {
    if (timeRange === 'Custom range' && !startDate) {
      setTimeRange(previousTimeRangeRef.current)
    }
    setDatePickerOpen(false)
  }

  const filtersActive = hasActiveFilters({
    timeRange,
    level,
    workflowIds,
    folderIds,
    triggers,
    searchQuery,
  })

  const handleClearFilters = () => {
    resetFilters()
    onSearchQueryChange('')
  }

  return (
    <div className='flex w-[240px] flex-col gap-4 p-3'>
      <div className='flex flex-col gap-[9px]'>
        <span className='text-[var(--text-muted)] text-small'>Status</span>
        <ChipCombobox
          options={statusOptions}
          multiSelect
          multiSelectValues={selectedStatuses}
          onMultiSelectChange={handleStatusChange}
          placeholder='All statuses'
          overlayContent={
            <span className='flex items-center gap-1.5 truncate text-[var(--text-primary)]'>
              {selectedStatusColor && (
                <div
                  className='flex-shrink-0 rounded-[3px]'
                  style={{ backgroundColor: selectedStatusColor, width: 8, height: 8 }}
                />
              )}
              <span className='truncate'>{statusDisplayLabel}</span>
            </span>
          }
          showAllOption
          allOptionLabel='All statuses'
          className='w-full'
        />
      </div>

      <div className='flex flex-col gap-[9px]'>
        <span className='text-[var(--text-muted)] text-small'>Workflow</span>
        <ChipCombobox
          options={workflowOptions}
          multiSelect
          multiSelectValues={workflowIds}
          onMultiSelectChange={setWorkflowIds}
          placeholder='All workflows'
          overlayContent={
            <span className='flex items-center gap-1.5 truncate text-[var(--text-primary)]'>
              {selectedWorkflow && (
                <Workflow className='size-[14px] flex-shrink-0 text-[var(--text-icon)]' />
              )}
              <span className='truncate'>{workflowDisplayLabel}</span>
            </span>
          }
          searchable
          searchPlaceholder='Search workflows...'
          showAllOption
          allOptionLabel='All workflows'
          className='w-full'
        />
      </div>

      <div className='flex flex-col gap-[9px]'>
        <span className='text-[var(--text-muted)] text-small'>Folder</span>
        <ChipCombobox
          options={folderOptions}
          multiSelect
          multiSelectValues={folderIds}
          onMultiSelectChange={setFolderIds}
          placeholder='All folders'
          overlayContent={
            <span className='truncate text-[var(--text-primary)]'>{folderDisplayLabel}</span>
          }
          searchable
          searchPlaceholder='Search folders...'
          showAllOption
          allOptionLabel='All folders'
          className='w-full'
        />
      </div>

      <div className='flex flex-col gap-[9px]'>
        <span className='text-[var(--text-muted)] text-small'>Trigger</span>
        <ChipCombobox
          options={triggerOptions}
          multiSelect
          multiSelectValues={triggers}
          onMultiSelectChange={setTriggers}
          placeholder='All triggers'
          overlayContent={
            <span className='truncate text-[var(--text-primary)]'>{triggerDisplayLabel}</span>
          }
          searchable
          searchPlaceholder='Search triggers...'
          showAllOption
          allOptionLabel='All triggers'
          className='w-full'
        />
      </div>

      <div className='flex flex-col gap-[9px]'>
        <span className='text-[var(--text-muted)] text-small'>Time Range</span>
        <div className='relative'>
          <ChipCombobox
            options={TIME_RANGE_OPTIONS}
            value={timeRange}
            onChange={handleTimeRangeChange}
            placeholder='All time'
            overlayContent={
              <span className='truncate text-[var(--text-primary)]'>{timeDisplayLabel}</span>
            }
            className='w-full'
            maxHeight={320}
          />
          <Popover
            open={datePickerOpen}
            onOpenChange={(isOpen) => {
              if (!isOpen) {
                if (dateRangeAppliedRef.current) {
                  dateRangeAppliedRef.current = false
                } else {
                  handleDatePickerCancel()
                }
              }
            }}
          >
            <PopoverAnchor className='pointer-events-none absolute inset-0' />
            <PopoverContent align='start' sideOffset={4} className='w-auto p-0'>
              <Calendar
                mode='range'
                showTime
                startDate={startDate}
                endDate={endDate}
                onRangeChange={handleDateRangeApply}
                onCancel={handleDatePickerCancel}
              />
            </PopoverContent>
          </Popover>
        </div>
      </div>

      {filtersActive && (
        <Button
          variant='active'
          onClick={handleClearFilters}
          className='h-[32px] w-full rounded-md'
        >
          Clear All Filters
        </Button>
      )}
    </div>
  )
}

function SuggestionButton({
  suggestion,
  index,
  highlighted,
  onHover,
  onSelect,
  showCategory,
}: {
  suggestion: Suggestion
  index: number
  highlighted: boolean
  onHover: (i: number) => void
  onSelect: (s: Suggestion) => void
  showCategory?: boolean
}) {
  return (
    <Button
      type='button'
      variant='ghost'
      data-index={index}
      className={cn(
        'h-auto w-full justify-start rounded-md px-3 py-2 text-left transition-colors hover-hover:bg-[var(--surface-5)]',
        highlighted && 'bg-[var(--surface-5)]'
      )}
      onMouseEnter={() => onHover(index)}
      onMouseDown={(e) => {
        e.preventDefault()
        onSelect(suggestion)
      }}
    >
      <div className='flex w-full items-center justify-between gap-3'>
        <div className='min-w-0 flex-1 truncate text-small'>{suggestion.label}</div>
        {showCategory && suggestion.value !== suggestion.label && (
          <div className='shrink-0 font-mono text-[var(--text-muted)] text-xs'>
            {suggestion.category === 'workflow' || suggestion.category === 'folder'
              ? `${suggestion.category}:`
              : ''}
          </div>
        )}
        {!showCategory && suggestion.description && (
          <div className='shrink-0 text-[var(--text-muted)] text-xs'>{suggestion.value}</div>
        )}
      </div>
    </Button>
  )
}
