import PropTypes from 'prop-types'
import { useState, useEffect, useContext, useRef, useCallback, useMemo, memo } from 'react'
import { Button, message, Popover, Typography, Space, Flex } from 'antd'
import { UserOutlined } from '@ant-design/icons'
import BellIcon from '../../Icons/BellIcon'
import MailCheckIcon from '../../Icons/MailCheckIcon'
import MailIcon from '../../Icons/MailIcon'
import { ApiServerContext } from '../context/ApiServerContext'
import { AuthContext } from '../context/AuthContext'
import { LoadingOutlined } from '@ant-design/icons'
import InfoCircleIcon from '../../Icons/InfoCircleIcon'

const { Text } = Typography

const UserNotifierToggle = memo(({
  type,
  objectData,
  size = 'middle',
  disabled = false,
  ...buttonProps
}) => {
  const {
    toggleUserNotifier,
    editUserNotifier,
    fetchUserNotifiersForObject,
    fetchAllUserNotifiersForObject
  } = useContext(ApiServerContext)
  const { userProfile, token, authInitialized } = useContext(AuthContext)
  const [isNotifying, setIsNotifying] = useState(false)
  const [loading, setLoading] = useState(false)
  const [initialLoad, setInitialLoad] = useState(true)
  const [allNotifiers, setAllNotifiers] = useState([])
  const [popoverOpen, setPopoverOpen] = useState(false)
  const [popoverLoading, setPopoverLoading] = useState(false)
  const [emailTogglingId, setEmailTogglingId] = useState(null)

  const objectId = objectData?._id
  const authReady = Boolean(token && authInitialized)

  const apiRef = useRef({
    fetchUserNotifiersForObject,
    fetchAllUserNotifiersForObject
  })
  apiRef.current = {
    fetchUserNotifiersForObject,
    fetchAllUserNotifiersForObject
  }

  useEffect(() => {
    if (!authReady || !objectId || !type) return

    const loadNotifierState = async () => {
      setInitialLoad(true)
      try {
        const { data } = await apiRef.current.fetchUserNotifiersForObject(objectId, type)
        setIsNotifying(data?.length > 0)
      } catch (error) {
        console.error('Error fetching user notifier state:', error)
      } finally {
        setInitialLoad(false)
      }
    }

    loadNotifierState()
  }, [authReady, objectId, type])

  useEffect(() => {
    if (!authReady || !objectId || !type || !popoverOpen) return

    const loadAllNotifiers = async () => {
      setPopoverLoading(true)
      try {
        const { data } = await apiRef.current.fetchAllUserNotifiersForObject(objectId, type)
        setAllNotifiers(data || [])
      } catch (error) {
        console.error('Error fetching all user notifiers:', error)
        setAllNotifiers([])
      } finally {
        setPopoverLoading(false)
      }
    }

    loadAllNotifiers()
  }, [authReady, objectId, type, popoverOpen])

  const handleClick = useCallback(async () => {
    if (!authReady || !objectId || !type || loading) return

    setLoading(true)
    try {
      const enabled = await toggleUserNotifier(objectId, type)
      setIsNotifying(enabled)
      if (popoverOpen) {
        const { data } = await fetchAllUserNotifiersForObject(objectId, type)
        setAllNotifiers(data || [])
      }
      message.success(
        enabled
          ? 'Notifications enabled for this object'
          : 'Notifications disabled for this object'
      )
    } catch (error) {
      console.error('Error toggling user notifier:', error)
      message.error('Failed to update notifications')
    } finally {
      setLoading(false)
    }
  }, [authReady, objectId, type, loading, popoverOpen, toggleUserNotifier, fetchAllUserNotifiersForObject])

  const getUserDisplayName = useCallback((user) => {
    if (!user) return 'Unknown'
    return (
      user.name ||
      user.username ||
      `${user.firstName || ''} ${user.lastName || ''}`.trim() ||
      user.email ||
      'Unknown'
    )
  }, [])

  const isCurrentUser = useCallback((user) => user?._id === userProfile?._id, [userProfile?._id])

  const handleEmailToggle = useCallback(async (item) => {
    if (!isCurrentUser(item.user) || emailTogglingId) return
    setEmailTogglingId(item._id)
    const newEmail = !item.email
    try {
      const result = await editUserNotifier(item._id, { email: newEmail })
      if (result) {
        setAllNotifiers((prev) =>
          prev.map((n) =>
            n._id === item._id ? { ...n, email: result.email ?? newEmail } : n
          )
        )
        message.success(
          (result.email ?? newEmail)
            ? 'Email notifications enabled'
            : 'Email notifications disabled'
        )
      }
    } catch (error) {
      console.error('Error toggling email:', error)
      message.error('Failed to update email notifications')
    } finally {
      setEmailTogglingId(null)
    }
  }, [isCurrentUser, emailTogglingId, editUserNotifier])

  const popoverContent = useMemo(
    () => (
      <Flex
        vertical
        justify='center'
        style={{ minWidth: 240, minHeight: 25 }}
        gap={'4px'}
      >
        {popoverLoading ? (
          <Space size={'small'}>
            <LoadingOutlined />
            <Text style={{ margin: 0 }}>Loading, please wait...</Text>
          </Space>
        ) : allNotifiers.length === 0 ? (
          <Space size={'small'}>
            <Text style={{ margin: 0 }} type='secondary'>
              <InfoCircleIcon />
            </Text>
            <Text style={{ margin: 0 }} type='secondary'>
              No users subscribed.
            </Text>
          </Space>
        ) : (
          <>
            {[...allNotifiers]
              .sort(
                (a, b) =>
                  (isCurrentUser(b.user) ? 1 : 0) -
                  (isCurrentUser(a.user) ? 1 : 0)
              )
              .map((item) => (
                <Flex key={item._id} justify='space-between' align='center'>
                  <Flex align='center' gap={'6px'}>
                    <UserOutlined />
                    <Text>{getUserDisplayName(item.user)}</Text>
                    {isCurrentUser(item.user) && (
                      <Text type='secondary'> (you)</Text>
                    )}
                  </Flex>
                  <Space size={'small'}>
                    <Button
                      type='text'
                      icon={
                        item.email ? (
                          <MailCheckIcon
                            style={{
                              color: 'var(--color-primary)'
                            }}
                          />
                        ) : (
                          <MailIcon />
                        )
                      }
                      size='small'
                      disabled={!isCurrentUser(item.user)}
                      loading={emailTogglingId === item._id}
                      onClick={() => handleEmailToggle(item)}
                    />
                  </Space>
                </Flex>
              ))}
          </>
        )}
      </Flex>
    ),
    [popoverLoading, allNotifiers, emailTogglingId, isCurrentUser, getUserDisplayName, handleEmailToggle]
  )

  return (
    <Popover
      content={popoverContent}
      title={null}
      trigger='hover'
      placement='bottomLeft'
      arrow={false}
      open={popoverOpen}
      onOpenChange={setPopoverOpen}
      styles={{ body: { padding: '10px 12.5px 10px 15px' } }}
    >
      <Button
        {...buttonProps}
        icon={
          <BellIcon
            style={{
              color: isNotifying ? 'var(--color-warning)' : undefined
            }}
          />
        }
        disabled={disabled || loading || initialLoad || !authReady}
        loading={loading || !authReady || !objectId || !type}
        onClick={handleClick}
        size={size}
        style={{ minWidth: size === 'small' ? 24 : undefined }}
      />
    </Popover>
  )
})

UserNotifierToggle.displayName = 'UserNotifierToggle'

UserNotifierToggle.propTypes = {
  type: PropTypes.string.isRequired,
  objectData: PropTypes.object.isRequired,
  disabled: PropTypes.bool,
  size: PropTypes.string
}

export default UserNotifierToggle
