import React, { useCallback, useContext, useEffect, useState } from 'react'
import PropTypes from 'prop-types'
import {
  Card,
  Button,
  Space,
  Typography,
  Flex,
  Modal,
  Form,
  Input,
  Switch,
  Spin,
  Alert,
  message,
  Divider,
  Tag,
  Dropdown
} from 'antd'
import { CaretLeftFilled, LoadingOutlined } from '@ant-design/icons'
import PlusIcon from '../../Icons/PlusIcon'
import BinIcon from '../../Icons/BinIcon'
import PersonIcon from '../../Icons/PersonIcon'
import TimeDisplay from './TimeDisplay'
import MarkdownDisplay from './MarkdownDisplay'
import axios from 'axios'
import config from '../../../config'
import { AuthContext } from '../context/AuthContext'
import { ApiServerContext } from '../context/ApiServerContext'
import InfoCircleIcon from '../../Icons/InfoCircleIcon'
import NoteTypeSelect from './NoteTypeSelect'
import IdDisplay from './IdDisplay'
import ReloadIcon from '../../Icons/ReloadIcon'
import ExclamationOctagonIcon from '../../Icons/ExclamationOctagonIcon'

const { Text, Title } = Typography
const { TextArea } = Input

const NoteItem = ({
  note,
  expandedNotes,
  setExpandedNotes,
  fetchData,
  onNewNote,
  onDeleteNote,
  userProfile,
  onChildNoteAdded
}) => {
  const [childNotes, setChildNotes] = useState({})
  const [loadingChildNotes, setLoadingChildNotes] = useState(null)

  const isExpanded = expandedNotes[note._id]
  const hasChildNotes = childNotes[note._id] && childNotes[note._id].length > 0
  const isThisNoteLoading = loadingChildNotes === note._id

  let transformValue = 'rotate(0deg)'
  if (isExpanded) {
    transformValue = 'rotate(-90deg)'
  }

  const handleNoteExpand = async (noteId) => {
    const newExpandedState = !expandedNotes[noteId]

    setExpandedNotes((prev) => ({
      ...prev,
      [noteId]: newExpandedState
    }))

    if (newExpandedState && !childNotes[noteId]) {
      setLoadingChildNotes(noteId)
      try {
        const childNotesData = await fetchData(noteId)
        setChildNotes((prev) => ({
          ...prev,
          [noteId]: childNotesData
        }))
      } catch (error) {
        console.error('Error fetching child notes:', error)
      } finally {
        setLoadingChildNotes(null)
      }
    }
  }

  const handleNewChildNote = () => {
    if (onNewNote) {
      onNewNote(note._id)
    }
  }

  const handleDeleteNote = () => {
    if (onDeleteNote) {
      onDeleteNote(note._id)
    }
  }

  // Reload child notes when a new child note is added
  const reloadChildNotes = useCallback(async () => {
    // Always fetch child notes when this function is called
    // This ensures child notes are loaded even if the parent wasn't expanded before
    setLoadingChildNotes(note._id)
    try {
      const childNotesData = await fetchData(note._id)
      setChildNotes((prev) => ({
        ...prev,
        [note._id]: childNotesData
      }))
    } catch (error) {
      console.error('Error fetching child notes:', error)
    } finally {
      setLoadingChildNotes(null)
    }
  }, [fetchData, note._id])

  // Listen for child note additions
  useEffect(() => {
    if (onChildNoteAdded) {
      onChildNoteAdded(note._id, reloadChildNotes)
    }
  }, [note._id, onChildNoteAdded, reloadChildNotes])

  // Check if the current user can delete this note
  const canDeleteNote = userProfile && userProfile._id === note.user._id

  const dropdownItems = [
    {
      key: 'new',
      icon: <PlusIcon />,
      label: 'New Note',
      onClick: handleNewChildNote
    }
  ]

  // Only add delete option if user owns the note
  if (canDeleteNote) {
    dropdownItems.push({
      key: 'delete',
      label: 'Delete Note',
      icon: <BinIcon />,
      onClick: handleDeleteNote,
      danger: true
    })
  }

  return (
    <Card
      key={note._id}
      size='small'
      style={{
        backgroundColor: note.noteType.color + '26',
        textAlign: 'left'
      }}
    >
      <Flex vertical gap={'small'}>
        <Flex gap={'middle'} align='start'>
          <Space>
            <PersonIcon />
            <Text style={{ whiteSpace: 'nowrap' }}>{note.user.name}:</Text>
          </Space>
          <div style={{ marginBottom: '4px' }}>
            <MarkdownDisplay content={note.content} />
          </div>
        </Flex>
        <Divider style={{ margin: 0 }} />
        <Flex wrap gap={'small'}>
          <Dropdown
            menu={{ items: dropdownItems }}
            trigger={['hover']}
            placement='bottomLeft'
          >
            <Button size='small'>Actions</Button>
          </Dropdown>
          <Space size={'small'} style={{ marginRight: 8 }}>
            <Text type='secondary'>Type:</Text>
            <Tag color={note.noteType.color} style={{ margin: 0 }}>
              {note.noteType.name}
            </Tag>
          </Space>
          <Space size={'small'} style={{ marginRight: 8 }}>
            <Text type='secondary'>User ID:</Text>
            <IdDisplay
              longId={false}
              id={note.user._id}
              type={'user'}
              showHyperlink={true}
            />
          </Space>
          <Space size={'small'} style={{ marginRight: 8 }}>
            <Text type='secondary'>Created At:</Text>
            <TimeDisplay dateTime={note.createdAt} showSince={true} />
          </Space>
          <Flex style={{ flexGrow: 1 }} justify='end'>
            <Space size={'small'}>
              <Button
                icon={
                  isThisNoteLoading ? <LoadingOutlined /> : <CaretLeftFilled />
                }
                size='small'
                type='text'
                loading={isThisNoteLoading}
                disabled={isThisNoteLoading}
                style={{
                  transform: transformValue,
                  transition: 'transform 0.2s ease'
                }}
                onClick={() => handleNoteExpand(note._id)}
              />
            </Space>
          </Flex>
        </Flex>
        {isExpanded && (
          <>
            <Flex vertical gap={'small'} style={{ flexGrow: 1 }}>
              {hasChildNotes ? (
                childNotes[note._id].map((childNote) => (
                  <NoteItem
                    key={childNote._id}
                    note={childNote}
                    expandedNotes={expandedNotes}
                    setExpandedNotes={setExpandedNotes}
                    fetchData={fetchData}
                    onNewNote={onNewNote}
                    onDeleteNote={onDeleteNote}
                    userProfile={userProfile}
                    onChildNoteAdded={onChildNoteAdded}
                  />
                ))
              ) : !isThisNoteLoading ? (
                <Card size='small'>
                  <Flex
                    justify='center'
                    gap={'small'}
                    style={{ height: '100%' }}
                    align='center'
                  >
                    <Text type='secondary'>
                      <InfoCircleIcon />
                    </Text>
                    <Text type='secondary'>No child notes.</Text>
                  </Flex>
                </Card>
              ) : null}
            </Flex>
          </>
        )}
        <Flex vertical gap={'middle'}></Flex>
      </Flex>
    </Card>
  )
}

NoteItem.propTypes = {
  note: PropTypes.object.isRequired,
  expandedNotes: PropTypes.object.isRequired,
  setExpandedNotes: PropTypes.func.isRequired,
  fetchData: PropTypes.func.isRequired,
  onNewNote: PropTypes.func,
  onDeleteNote: PropTypes.func,
  userProfile: PropTypes.object,
  onChildNoteAdded: PropTypes.func
}

const NotesPanel = ({ _id, onNewNote, type }) => {
  const [newNoteOpen, setNewNoteOpen] = useState(false)
  const [showMarkdown, setShowMarkdown] = useState(false)
  const [loading, setLoading] = useState(true)
  const [initialized, setInitialized] = useState(false)
  const [messageApi, contextHolder] = message.useMessage()
  const [newNoteFormLoading, setNewNoteFormLoading] = useState(false)
  const [newNoteFormValues, setNewNoteFormValues] = useState({})
  const [deleteNoteLoading, setDeleteNoteLoading] = useState(false)
  const [doneEnabled, setDoneEnabled] = useState(false)
  const [error, setError] = useState(null)
  const [notes, setNotes] = useState(null)
  const [expandedNotes, setExpandedNotes] = useState({})
  const [newNoteForm] = Form.useForm()
  const [selectedParentId, setSelectedParentId] = useState(null)
  const [selectedParentType, setSelectedParentType] = useState(null)
  const [childNoteCallbacks, setChildNoteCallbacks] = useState({})
  const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false)
  const [noteToDelete, setNoteToDelete] = useState(null)

  const newNoteFormUpdateValues = Form.useWatch([], newNoteForm)

  React.useEffect(() => {
    newNoteForm
      .validateFields({
        validateOnly: true
      })
      .then(() => setDoneEnabled(true))
      .catch(() => setDoneEnabled(false))
  }, [newNoteForm, newNoteFormUpdateValues])

  const { token, userProfile } = useContext(AuthContext)
  const { fetchNotes } = useContext(ApiServerContext)

  const fetchData = useCallback(
    async (id) => {
      try {
        const newData = await fetchNotes(id)
        return newData
      } catch (error) {
        setError(error)
        return null
      }
    },
    [fetchNotes]
  )

  const handleNewChildNote = useCallback(
    (parentId) => {
      setSelectedParentId(parentId)
      setSelectedParentType('note')
      setNewNoteOpen(true)
      newNoteForm.resetFields()
      setNewNoteFormValues({})
    },
    [newNoteForm]
  )

  const generateNotes = useCallback(
    async (id) => {
      const notesData = await fetchData(id)
      setLoading(false)

      if (notesData == null) {
        return null
      }

      if (notesData.length <= 0) {
        return (
          <Card>
            <Flex
              justify='center'
              gap={'small'}
              style={{ height: '100%' }}
              align='center'
            >
              <Text type='secondary'>
                <InfoCircleIcon />
              </Text>
              <Text type='secondary'>No notes added.</Text>
            </Flex>
          </Card>
        )
      }

      return notesData.map((note) => (
        <NoteItem
          key={note._id}
          note={note}
          expandedNotes={expandedNotes}
          setExpandedNotes={setExpandedNotes}
          fetchData={fetchData}
          onNewNote={handleNewChildNote}
          onDeleteNote={handleDeleteNote}
          userProfile={userProfile}
          onChildNoteAdded={(noteId, callback) => {
            setChildNoteCallbacks((prev) => ({
              ...prev,
              [noteId]: callback
            }))
          }}
        />
      ))
    },
    [loading, fetchData, expandedNotes, userProfile, handleNewChildNote]
  )

  const handleNewNote = async () => {
    setNewNoteFormLoading(true)
    try {
      await axios.post(
        `${config.backendUrl}/notes`,
        {
          ...newNoteFormValues,
          parent: selectedParentId,
          parentType: selectedParentType
        },
        {
          withCredentials: true
        }
      )
      setNewNoteOpen(false)
      messageApi.success('Added a new note.')

      // If this is a child note, expand the parent and reload child notes
      if (selectedParentId) {
        // Ensure parent is expanded
        setExpandedNotes((prev) => ({
          ...prev,
          [selectedParentId]: true
        }))

        // Add a small delay to ensure state update has taken effect
        setTimeout(() => {
          // Reload child notes for the parent
          if (childNoteCallbacks[selectedParentId]) {
            childNoteCallbacks[selectedParentId]()
          }
        }, 100)
      } else {
        // If it's a top-level note, reload all notes
        setLoading(true)
        handleReloadData()
      }

      setSelectedParentId(null)
    } catch (error) {
      messageApi.error('Error creating new note: ' + error.message)
    } finally {
      setNewNoteFormLoading(false)
    }
  }

  const handleDeleteNote = async (noteId) => {
    setNoteToDelete(noteId)
    setDeleteConfirmOpen(true)
  }

  const confirmDeleteNote = async () => {
    if (!noteToDelete) return
    setDeleteNoteLoading(true)

    try {
      await axios.delete(`${config.backendUrl}/notes/${noteToDelete}`, {
        withCredentials: true
      })
      messageApi.success('Note deleted successfully.')

      // Reload all top-level notes
      setLoading(true)
      handleReloadData()

      // Reload child notes for all expanded parents to ensure UI stays in sync
      const expandedNoteIds = Object.keys(expandedNotes).filter(
        (id) => expandedNotes[id]
      )
      for (const parentId of expandedNoteIds) {
        if (childNoteCallbacks[parentId]) {
          childNoteCallbacks[parentId]()
        }
      }
    } catch (error) {
      messageApi.error('Error deleting note: ' + error.message)
    } finally {
      setDeleteNoteLoading(false)
      setDeleteConfirmOpen(false)
      setNoteToDelete(null)
    }
  }

  const cancelDeleteNote = () => {
    setDeleteConfirmOpen(false)
    setNoteToDelete(null)
  }

  const handleReloadData = useCallback(async () => {
    setNotes(await generateNotes(_id))
  }, [_id, generateNotes])

  useEffect(() => {
    if (token != null && !initialized) {
      handleReloadData()
      setInitialized(true)
    }
  }, [token, handleReloadData, initialized])

  const handleModalOk = async () => {
    try {
      const values = await newNoteForm.validateFields()
      onNewNote(values)
      newNoteForm.resetFields()
      setNewNoteOpen(false)
      setShowMarkdown(false)
    } catch (error) {
      console.error('Validation failed:', error)
    }
  }

  const handleModalCancel = () => {
    newNoteForm.resetFields()
    setNewNoteOpen(false)
    setShowMarkdown(false)
    setSelectedParentId(null)
  }

  const actionItems = {
    items: [
      {
        label: 'New Note',
        key: 'newNote',
        icon: <PlusIcon />
      },
      { type: 'divider' },
      {
        label: 'Reload Notes',
        key: 'reloadNotes',
        icon: <ReloadIcon />
      }
    ],
    onClick: ({ key }) => {
      if (key === 'reloadNotes') {
        setLoading(true)
        handleReloadData()
      } else if (key === 'newNote') {
        setSelectedParentId(_id)
        setSelectedParentType(type)
        setNewNoteOpen(true)
        newNoteForm.resetFields()
        setNewNoteFormValues({})
      }
    }
  }

  return (
    <Flex vertical gap='large' style={{ width: '100%' }}>
      {contextHolder}
      <Flex justify='space-between'>
        <Space size={'small'}>
          <Dropdown menu={actionItems} disabled={loading}>
            <Button disabled={loading}>Actions</Button>
          </Dropdown>
        </Space>
        <Space size={'small'}>
          <Button
            type='primary'
            icon={<PlusIcon />}
            disabled={loading}
            onClick={() => {
              setSelectedParentId(_id)
              setSelectedParentType(type)
              setNewNoteOpen(true)
              newNoteForm.resetFields()
              setNewNoteFormValues({})
            }}
          />
        </Space>
      </Flex>

      <Space direction='vertical' size='middle' style={{ width: '100%' }}>
        <Spin indicator={<LoadingOutlined />} spinning={loading}>
          {error ? (
            <Alert message={error?.message} type='error' showIcon={true} />
          ) : (
            <Flex vertical gap={'middle'}>
              {notes}
            </Flex>
          )}
        </Spin>
      </Space>

      <Modal
        open={newNoteOpen}
        onOk={handleModalOk}
        onCancel={handleModalCancel}
        width={800}
        closeIcon={false}
        destroyOnHidden={true}
        footer={false}
      >
        <Flex vertical gap='large'>
          <Flex vertical gap='middle'>
            <Flex align='center' justify='space-between'>
              <Title level={2} style={{ marginTop: 0, marginBottom: 4 }}>
                New Note
              </Title>
              <Space gap={'small'}>
                <Text type='secondary'>Markdown:</Text>
                <Switch onChange={setShowMarkdown} size='small' />
              </Space>
            </Flex>
            <Form
              form={newNoteForm}
              layout='vertical'
              onFinish={handleNewNote}
              initialValues={{ content: '' }}
              onValuesChange={(changedValues) =>
                setNewNoteFormValues((prevValues) => ({
                  ...prevValues,
                  ...changedValues
                }))
              }
            >
              <Flex vertical gap={'large'}>
                <Flex gap='middle' wrap>
                  <Form.Item
                    name='content'
                    rules={[{ required: true, message: '' }]}
                    style={{ margin: 0, flexGrow: 1, minWidth: '300px' }}
                  >
                    <TextArea
                      rows={6}
                      placeholder='Enter note content'
                      style={{ resize: 'none' }}
                    />
                  </Form.Item>

                  {showMarkdown && (
                    <Card
                      style={{
                        flexGrow: 1,
                        minWidth: '300px',
                        backgroundColor: () => {
                          if (newNoteFormValues?.noteType?.color) {
                            return newNoteFormValues.noteType.color + '26'
                          }
                        }
                      }}
                    >
                      <MarkdownDisplay
                        content={newNoteForm.getFieldValue('content') || ''}
                      />
                    </Card>
                  )}
                </Flex>
                <Form.Item
                  name='noteType'
                  style={{ margin: 0 }}
                  rules={[
                    { required: true, message: 'Please select a note type' }
                  ]}
                >
                  <NoteTypeSelect />
                </Form.Item>
              </Flex>
            </Form>
          </Flex>
          <Flex justify='end'>
            <Button
              style={{ margin: '0 8px' }}
              disabled={newNoteFormLoading}
              onClick={() => {
                setNewNoteOpen(false)
              }}
            >
              Cancel
            </Button>

            <Button
              type='primary'
              loading={newNoteFormLoading}
              onClick={() => {
                newNoteForm.submit()
              }}
              disabled={newNoteFormLoading || !doneEnabled}
            >
              Done
            </Button>
          </Flex>
        </Flex>
      </Modal>

      <Modal
        open={deleteConfirmOpen}
        title={
          <Space size={'middle'}>
            <ExclamationOctagonIcon />
            Confirm Delete
          </Space>
        }
        onOk={confirmDeleteNote}
        onCancel={cancelDeleteNote}
        okText='Delete'
        cancelText='Cancel'
        okType='danger'
        closable={false}
        centered
        maskClosable={false}
        footer={[
          <Button
            key='cancel'
            onClick={cancelDeleteNote}
            disabled={deleteNoteLoading}
          >
            Cancel
          </Button>,
          <Button
            key='delete'
            type='primary'
            danger
            onClick={confirmDeleteNote}
            loading={deleteNoteLoading}
            disabled={deleteNoteLoading}
          >
            Delete
          </Button>
        ]}
      >
        <Text>Are you sure you want to delete this note?</Text>
      </Modal>
    </Flex>
  )
}

NotesPanel.propTypes = {
  _id: PropTypes.string.isRequired,
  type: PropTypes.string.isRequired,
  onNewNote: PropTypes.func
}

export default NotesPanel
