import { Input, Flex, List, Typography, Modal, Tag } from 'antd'
import {
  createContext,
  useContext,
  useEffect,
  useMemo,
  useRef,
  useState
} from 'react'
import PropTypes from 'prop-types'
import { useLocation, useNavigate } from 'react-router-dom'

import { getModelByName } from '../../../database/ObjectModels'
import { AuthContext } from './AuthContext'
import {
  buildActionUrl,
  stripActionParams
} from '../../../utils/modelActions'

const ActionsModalContext = createContext()

// Remove action query params from a URL so we don't navigate to the same URL again
const stripActionParam = stripActionParams

// Flatten nested actions (including children) into a single list
const flattenActions = (actions, parentLabel = '') => {
  if (!Array.isArray(actions)) return []

  const flat = []

  actions.forEach((action) => {
    if (!action || action.type === 'divider') {
      return
    }

    const hasUrl =
      typeof action.url === 'function' ||
      action.type === 'page' ||
      action.type === 'modal'
    const hasChildren =
      Array.isArray(action.children) && action.children.length > 0

    const currentLabel = action.label || action.name || ''
    const fullLabel = parentLabel
      ? `${parentLabel} / ${currentLabel}`
      : currentLabel

    // Only push actions that are actually runnable
    if (hasUrl) {
      flat.push({
        ...action,
        key: action.key || action.name || fullLabel,
        fullLabel
      })
    }

    if (hasChildren) {
      flat.push(...flattenActions(action.children, fullLabel))
    }
  })

  return flat
}

const ActionsModalProvider = ({ children }) => {
  const { Text } = Typography
  const navigate = useNavigate()
  const location = useLocation()
  const { userProfile } = useContext(AuthContext)

  const [visible, setVisible] = useState(false)
  const [query, setQuery] = useState('')
  const [context, setContext] = useState({
    id: null,
    type: null,
    objectData: null
  })

  const inputRef = useRef(null)

  const showActionsModal = (id, type, objectData = null) => {
    setContext({ id, type, objectData })
    setQuery('')
    setVisible(true)
  }

  const hideActionsModal = () => {
    setVisible(false)
    setQuery('')
  }

  // Focus and select text in input when modal becomes visible
  useEffect(() => {
    // Use a small timeout to ensure the modal is fully rendered and visible
    setTimeout(() => {
      if (visible) {
        if (visible && inputRef.current) {
          const input = inputRef.current.input
          if (input) {
            input.focus()
            input.select() // Select all text
          }
        }
      }
    }, 50)
  }, [visible])

  const model = context.type ? getModelByName(context.type) : null
  const ModelIcon = model?.icon || null
  const modelLabel = model?.label || model?.name || ''

  const flattenedActions = useMemo(
    () => flattenActions(model?.actions || []),
    [model]
  )

  const currentUrlWithoutActions = stripActionParam(
    location.pathname,
    location.search
  )

  const getActionDisabled = (action) => {
    const { id, objectData } = context
    if (!action) return true

    let disabled = false
    const url = buildActionUrl(
      getModelByName(context.type),
      action,
      id,
      location.pathname,
      location.search
    )

    // Match ObjectActions default disabling behaviour
    if (url && url === currentUrlWithoutActions) {
      disabled = true
    }

    if (typeof action.disabled !== 'undefined') {
      if (typeof action.disabled === 'function') {
        disabled = action.disabled({ ...objectData, _user: userProfile })
      } else {
        disabled = action.disabled
      }
    }

    return disabled
  }

  const getVisibleDisabled = (action) => {
    const { objectData } = context
    if (!action) return true

    let visible = true

    if (typeof action.visible !== 'undefined') {
      if (typeof action.visible === 'function') {
        visible = action.visible(objectData)
      } else {
        visible = action.visible
      }
    }

    return visible
  }

  const normalizedQuery = query.trim().toLowerCase()

  const filteredActions = flattenedActions.filter((action) => {
    if (!normalizedQuery) return true

    const haystack = [
      action.fullLabel || '',
      action.label || '',
      action.name || '',
      modelLabel
    ]
      .join(' ')
      .toLowerCase()
    return haystack.includes(normalizedQuery)
  })

  const runAction = (action) => {
    if (!action) return
    if (getActionDisabled(action)) return

    const { id } = context
    const model = getModelByName(context.type)
    const targetUrl = buildActionUrl(
      model,
      action,
      id,
      location.pathname,
      location.search
    )
    if (targetUrl && targetUrl !== '#') {
      navigate(targetUrl)
      hideActionsModal()
    }
  }

  const handleKeyDown = (e) => {
    if (!filteredActions.length) return

    // Enter triggers first visible action
    if (e.key === 'Enter') {
      e.preventDefault()
      const first = filteredActions[0]
      runAction(first)
      return
    }

    // Number keys 1-9 trigger corresponding actions
    if (/^[1-9]$/.test(e.key)) {
      e.preventDefault()
      const index = parseInt(e.key, 10)
      if (index < filteredActions.length) {
        const action = filteredActions[index]
        runAction(action)
      }
    }
  }

  return (
    <ActionsModalContext.Provider value={{ showActionsModal }}>
      <Modal
        open={visible}
        onCancel={hideActionsModal}
        closeIcon={null}
        footer={null}
        width={700}
        styles={{ content: { padding: 0, borderRadius: '12px' } }}
        destroyOnHidden={true}
      >
        <Flex vertical>
          <Input
            ref={inputRef}
            addonBefore={
              <Text style={{ fontSize: '20px' }}>
                <ModelIcon />
              </Text>
            }
            placeholder='Search actions...'
            size='large'
            value={query}
            onChange={(e) => setQuery(e.target.value)}
            onKeyDown={handleKeyDown}
          />

          {filteredActions.length > 0 && (
            <div
              style={{
                marginLeft: '14px',
                marginRight: '14px'
              }}
            >
              <List
                dataSource={filteredActions.filter((action) =>
                  getVisibleDisabled(action)
                )}
                renderItem={(action, index) => {
                  const Icon = action.icon
                  const disabled = getActionDisabled(action)

                  let shortcutText = ''
                  if (index === 0) {
                    shortcutText = 'ENTER'
                  } else if (index <= 9) {
                    shortcutText = index.toString()
                  }

                  return (
                    <List.Item
                      onClick={() => !disabled && runAction(action)}
                      style={{
                        cursor: disabled ? 'not-allowed' : 'pointer',
                        opacity: disabled ? 0.5 : 1
                      }}
                    >
                      <Flex
                        gap='middle'
                        style={{ width: '100%' }}
                        align='center'
                        justify='space-between'
                      >
                        <Flex
                          gap='small'
                          align='center'
                          style={{ flexGrow: 1, minWidth: 0 }}
                        >
                          {Icon ? <Icon style={{ fontSize: '18px' }} /> : null}
                          <Flex vertical style={{ flexGrow: 1, minWidth: 0 }}>
                            <Text
                              ellipsis
                              style={{
                                maxWidth: 320,
                                width: '100%'
                              }}
                            >
                              {action.fullLabel || action.label || action.name}
                            </Text>
                          </Flex>
                        </Flex>
                        <Flex gap='small' align='center'>
                          {action.danger && <Tag color='red'>Danger</Tag>}
                          {shortcutText && <Text keyboard>{shortcutText}</Text>}
                        </Flex>
                      </Flex>
                    </List.Item>
                  )
                }}
              />
            </div>
          )}
        </Flex>
      </Modal>
      {children}
    </ActionsModalContext.Provider>
  )
}

ActionsModalProvider.propTypes = {
  children: PropTypes.node.isRequired
}

const useActionsModal = () => useContext(ActionsModalContext)

// eslint-disable-next-line react-refresh/only-export-components
export { ActionsModalProvider, ActionsModalContext, useActionsModal }
