import React, { useState, useRef, useEffect } from 'react'
import ReactMarkdown from 'react-markdown'

const QUICK_REACTIONS = ['👍', '❤️', '🔥', '😂', '👏', '😮']

export default function MessageBubble({ message, isMine, showAvatar, endsSequence = true, isNewlyArrived = false, prefersReducedMotion = false, onReact, onUnreact, onEdit, onDelete = null, onReport = null, onOpenImage = null, seenText = null }) {
  const [showPicker, setShowPicker] = useState(false)
  const [showActions, setShowActions] = useState(false)
  const [editing, setEditing] = useState(false)
  const [editBody, setEditBody] = useState(message.body ?? '')
  const [savingEdit, setSavingEdit] = useState(false)
  const [isArrivalVisible, setIsArrivalVisible] = useState(true)
  const editRef = useRef(null)

  const isDeleted = !!message.deleted_at
  const isEdited = !!message.edited_at
  const username = message.sender?.username ?? 'Unknown'
  const time = formatTime(message.created_at)
  const initials = username.charAt(0).toUpperCase()

  useEffect(() => {
    if (editing) {
      editRef.current?.focus()
      editRef.current?.setSelectionRange(editBody.length, editBody.length)
    }
  }, [editing, editBody.length])

  useEffect(() => {
    if (prefersReducedMotion || !isNewlyArrived) {
      setIsArrivalVisible(true)
      return undefined
    }

    setIsArrivalVisible(false)
    const frame = window.requestAnimationFrame(() => setIsArrivalVisible(true))
    return () => window.cancelAnimationFrame(frame)
  }, [isNewlyArrived, prefersReducedMotion])

  const reactionGroups = groupReactions(message.reactions ?? [])

  const handleSaveEdit = async () => {
    const trimmed = editBody.trim()
    if (!trimmed || trimmed === message.body || savingEdit) return
    setSavingEdit(true)
    try {
      await onEdit(message.id, trimmed)
      setEditing(false)
    } finally {
      setSavingEdit(false)
    }
  }

  const handleEditKeyDown = (e) => {
    if (e.key === 'Enter' && !e.shiftKey) {
      e.preventDefault()
      handleSaveEdit()
    }

    if (e.key === 'Escape') {
      setEditing(false)
      setEditBody(message.body)
    }
  }

  return (
    <div
      id={message?.id ? `message-${message.id}` : undefined}
      className={`group flex items-end gap-2.5 sm:gap-3 ${isMine ? 'flex-row-reverse' : 'flex-row'} ${showAvatar ? 'mt-4' : 'mt-1'}`}
      style={prefersReducedMotion ? undefined : {
        opacity: isArrivalVisible ? 1 : 0.55,
        transform: isArrivalVisible ? 'translateY(0px)' : 'translateY(10px)',
        filter: isNewlyArrived && isArrivalVisible ? 'drop-shadow(0 0 20px rgba(56,189,248,0.12))' : 'none',
        transition: 'opacity 260ms ease, transform 320ms ease, filter 900ms ease',
      }}
      onMouseEnter={() => !isDeleted && !editing && setShowPicker(true)}
      onMouseLeave={() => {
        setShowPicker(false)
        setShowActions(false)
      }}
    >
      <div className={`h-9 w-9 shrink-0 ${showAvatar ? 'visible' : 'invisible'}`}>
        <div className={`flex h-9 w-9 items-center justify-center rounded-2xl text-xs font-semibold text-white shadow-[0_10px_20px_rgba(0,0,0,0.18)] ${isMine ? 'bg-gradient-to-br from-sky-500 to-cyan-500' : 'bg-gradient-to-br from-violet-500 to-fuchsia-600'}`}>
          {initials}
        </div>
      </div>

      <div className={`flex max-w-[84%] flex-col sm:max-w-[75%] ${isMine ? 'items-end' : 'items-start'}`}>
        {showAvatar ? (
          <div className={`mb-1.5 flex items-center gap-2 ${isMine ? 'flex-row-reverse' : ''}`}>
            <span className="text-xs font-medium text-white/78">{username}</span>
            <span className="text-[11px] text-white/30">{time}</span>
          </div>
        ) : null}

        <div className="relative">
          {!editing && !isDeleted ? (
            <button
              type="button"
              onClick={() => setShowActions((prev) => !prev)}
              className={`absolute z-[1] inline-flex h-8 w-8 items-center justify-center rounded-full border border-white/[0.08] bg-[#0b1220]/88 text-white/40 shadow-[0_10px_20px_rgba(0,0,0,0.18)] transition hover:bg-[#11192a] hover:text-white ${isMine ? '-left-3 top-2 md:opacity-0 md:group-hover:opacity-100' : '-right-3 top-2 md:opacity-0 md:group-hover:opacity-100'}`}
              aria-label="Message actions"
            >
              <i className="fa-solid fa-ellipsis text-[11px]" />
            </button>
          ) : null}

          {editing ? (
            <div className="w-72">
              <textarea
                ref={editRef}
                value={editBody}
                onChange={(e) => setEditBody(e.target.value)}
                onKeyDown={handleEditKeyDown}
                rows={3}
                maxLength={5000}
                className="w-full resize-none rounded-2xl border border-sky-400/30 bg-black/20 px-3 py-2 text-sm text-white outline-none transition focus:border-sky-300/40"
              />
              <div className="mt-2 flex justify-end gap-2">
                <button
                  type="button"
                  onClick={() => {
                    setEditing(false)
                    setEditBody(message.body)
                  }}
                  className="text-xs text-white/35 transition hover:text-white/65"
                >
                  Cancel
                </button>
                <button
                  type="button"
                  onClick={handleSaveEdit}
                  disabled={savingEdit || !editBody.trim() || editBody.trim() === message.body}
                  className="text-xs font-medium text-sky-300 transition hover:text-sky-200 disabled:opacity-40"
                >
                  {savingEdit ? 'Saving…' : 'Save'}
                </button>
              </div>
            </div>
          ) : (
            <div
              className={`px-4 py-3 text-sm leading-relaxed shadow-[0_14px_35px_rgba(0,0,0,0.16)] ${bubbleShape({ isMine, showAvatar, endsSequence })} ${isMine ? 'border border-sky-400/24 bg-sky-500/16 text-white' : 'border border-white/[0.06] bg-white/[0.04] text-white/88'} ${isDeleted ? 'italic opacity-60' : ''} ${message._optimistic ? 'opacity-70' : ''}`}
            >
              {isDeleted ? (
                <span>This message was deleted.</span>
              ) : (
                <>
                  {message.attachments?.length > 0 ? (
                    <AttachmentCluster attachments={message.attachments} isMine={isMine} onOpenImage={onOpenImage} />
                  ) : null}

                  <div className="prose prose-invert prose-sm max-w-none prose-headings:text-white prose-li:text-inherit prose-p:my-0 prose-pre:my-1 prose-strong:text-white text-white/90">
                    <ReactMarkdown
                      allowedElements={['p', 'strong', 'em', 'code', 'pre', 'ul', 'ol', 'li', 'blockquote', 'a', 'br']}
                      unwrapDisallowed
                      components={{
                        a: ({ href, children }) => (
                          <a
                            href={href}
                            target="_blank"
                            rel="noopener noreferrer nofollow"
                            className={isMine ? 'text-sky-100 underline' : 'text-sky-300 underline'}
                          >
                            {children}
                          </a>
                        ),
                        code: ({ children, className }) => className
                          ? <code className={`${className} text-xs`}>{children}</code>
                          : <code className={`rounded px-1 py-0.5 text-xs ${isMine ? 'bg-sky-500/20' : 'bg-white/[0.08]'}`}>{children}</code>,
                      }}
                    >
                      {message.body}
                    </ReactMarkdown>
                  </div>

                  {isEdited ? (
                    <span className={`ml-1 text-xs ${isMine ? 'text-sky-100/80' : 'text-white/40'}`}>(edited)</span>
                  ) : null}
                </>
              )}
            </div>
          )}

          {(showPicker || showActions) && !editing && !isDeleted ? (
            <div
              className={`absolute bottom-full z-10 mb-2 flex items-center gap-1 whitespace-nowrap rounded-full border border-white/[0.08] bg-[#0b1220] px-2 py-1 shadow-[0_20px_40px_rgba(0,0,0,0.35)] ${isMine ? 'right-0' : 'left-0'}`}
              onMouseEnter={() => setShowPicker(true)}
              onMouseLeave={() => {
                setShowPicker(false)
                setShowActions(false)
              }}
            >
              {QUICK_REACTIONS.map((emoji) => (
                <button key={emoji} onClick={() => {
                  onReact(message.id, emoji)
                  setShowActions(false)
                }} className="inline-flex h-8 w-8 items-center justify-center rounded-full text-base transition-transform hover:scale-125" title={`React ${emoji}`}>
                  {emoji}
                </button>
              ))}
              {isMine ? (
                <>
                  <button
                    type="button"
                    onClick={() => {
                      setEditing(true)
                      setShowPicker(false)
                      setShowActions(false)
                    }}
                    className="ml-1 inline-flex h-8 w-8 items-center justify-center rounded-full text-white/35 transition hover:bg-white/[0.06] hover:text-white/80"
                    title="Edit message"
                  >
                    <svg xmlns="http://www.w3.org/2000/svg" className="h-3.5 w-3.5" viewBox="0 0 20 20" fill="currentColor">
                      <path d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z" />
                    </svg>
                  </button>
                  {onDelete ? (
                    <button
                      type="button"
                      onClick={() => {
                        onDelete(message.id)
                        setShowPicker(false)
                        setShowActions(false)
                      }}
                      className="inline-flex h-8 w-8 items-center justify-center rounded-full text-white/35 transition hover:bg-rose-500/10 hover:text-rose-300"
                      title="Delete message"
                    >
                      <i className="fa-solid fa-trash text-[11px]" />
                    </button>
                  ) : null}
                </>
              ) : null}
              {!isMine && onReport ? (
                <button
                  type="button"
                  onClick={() => {
                    onReport(message.id)
                    setShowPicker(false)
                    setShowActions(false)
                  }}
                  className="ml-1 inline-flex h-8 w-8 items-center justify-center rounded-full text-white/35 transition hover:bg-rose-500/10 hover:text-rose-300"
                  title="Report message"
                >
                  ⚑
                </button>
              ) : null}
            </div>
          ) : null}

        </div>

        {reactionGroups.length > 0 && !isDeleted ? (
          <div className={`mt-1 flex flex-wrap gap-1 ${isMine ? 'justify-end' : 'justify-start'} ${endsSequence ? '' : 'mb-0.5'}`}>
            {reactionGroups.map(({ emoji, count, iReacted }) => (
              <button
                key={emoji}
                onClick={() => (iReacted ? onUnreact(message.id, emoji) : onReact(message.id, emoji))}
                title={iReacted ? 'Remove reaction' : `React ${emoji}`}
                className={`flex items-center gap-0.5 rounded-full px-1.5 py-0.5 text-xs transition-colors ${iReacted ? 'border border-sky-400/20 bg-sky-500/14 text-sky-100' : 'border border-white/[0.08] bg-white/[0.04] text-white/55 hover:bg-white/[0.08] hover:text-white'}`}
              >
                <span>{emoji}</span>
                <span>{count}</span>
              </button>
            ))}
          </div>
        ) : null}

        {isMine && seenText ? (
          <div className="mt-1 text-[11px] text-white/30">
            {seenText}
          </div>
        ) : null}
      </div>
    </div>
  )
}

function formatTime(iso) {
  return new Date(iso).toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' })
}

function bubbleShape({ isMine, showAvatar, endsSequence }) {
  if (isMine) {
    return `${showAvatar ? 'rounded-t-[24px]' : 'rounded-tl-[24px] rounded-tr-[14px]'} ${endsSequence ? 'rounded-bl-[24px] rounded-br-[8px]' : 'rounded-bl-[24px] rounded-br-[14px]'}`
  }

  return `${showAvatar ? 'rounded-t-[24px]' : 'rounded-tr-[24px] rounded-tl-[14px]'} ${endsSequence ? 'rounded-br-[24px] rounded-bl-[8px]' : 'rounded-br-[24px] rounded-bl-[14px]'}`
}

function AttachmentCluster({ attachments, isMine, onOpenImage }) {
  const images = attachments.filter((attachment) => attachment.type === 'image')
  const files = attachments.filter((attachment) => attachment.type !== 'image')

  return (
    <div className="mb-3 space-y-2.5">
      {images.length > 0 ? <AttachmentImageGrid images={images} onOpenImage={onOpenImage} /> : null}
      {files.length > 0 ? <AttachmentFileStack files={files} isMine={isMine} /> : null}
    </div>
  )
}

function AttachmentImageGrid({ images, onOpenImage }) {
  const gridClass = images.length === 1 ? 'grid-cols-1' : 'grid-cols-2'

  return (
    <div className={`grid gap-2 ${gridClass}`}>
      {images.slice(0, 4).map((attachment, index) => {
        const remaining = images.length - 4
        const showOverlay = remaining > 0 && index === 3

        return (
          <button
            key={attachment.id}
            type="button"
            onClick={() => onOpenImage?.({
              id: attachment.id,
              original_name: attachment.original_name,
              url: `/messages/attachments/${attachment.id}`,
            })}
            className={`group/image relative overflow-hidden rounded-[20px] border border-white/15 bg-black/20 ${images.length === 1 ? 'max-w-md' : ''}`}
          >
            <img
              src={`/messages/attachments/${attachment.id}`}
              alt={attachment.original_name}
              className={`w-full object-cover transition duration-200 group-hover/image:scale-[1.02] ${images.length === 1 ? 'max-h-72' : 'h-32 sm:h-36'}`}
              loading="lazy"
            />
            <div className="absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/60 to-transparent px-3 py-2 text-left text-xs text-white/80">
              <span className="line-clamp-1">{attachment.original_name}</span>
            </div>
            {showOverlay ? (
              <div className="absolute inset-0 flex items-center justify-center bg-black/45 text-lg font-semibold text-white">
                +{remaining}
              </div>
            ) : null}
          </button>
        )
      })}
    </div>
  )
}

function AttachmentFileStack({ files, isMine }) {
  return (
    <div className={`rounded-[20px] border px-3 py-3 ${isMine ? 'border-sky-400/18 bg-sky-500/10' : 'border-white/[0.08] bg-black/20'}`}>
      <div className="mb-2 flex items-center justify-between gap-3">
        <span className="text-[11px] font-semibold uppercase tracking-[0.16em] text-white/45">Files</span>
        <span className="text-[11px] text-white/35">{files.length}</span>
      </div>
      <div className="space-y-2">
        {files.map((attachment) => (
          <a
            key={attachment.id}
            href={`/messages/attachments/${attachment.id}`}
            target="_blank"
            rel="noopener noreferrer"
            className={`flex items-center gap-3 rounded-2xl border px-3 py-2 text-left text-xs transition hover:translate-x-[1px] ${isMine ? 'border-sky-400/12 bg-sky-500/10 text-sky-50 hover:bg-sky-500/14' : 'border-white/[0.08] bg-white/[0.04] text-white/80 hover:bg-white/[0.06]'}`}
          >
            <span className={`inline-flex h-9 w-9 items-center justify-center rounded-xl ${isMine ? 'bg-sky-500/16 text-sky-100' : 'bg-white/[0.08] text-white/70'}`}>
              <i className="fa-solid fa-paperclip text-[11px]" />
            </span>
            <span className="min-w-0 flex-1 truncate">{attachment.original_name}</span>
            <i className="fa-solid fa-arrow-up-right-from-square text-[10px] opacity-60" />
          </a>
        ))}
      </div>
    </div>
  )
}

function groupReactions(reactions) {
  const map = new Map()
  for (const reaction of reactions) {
    if (!map.has(reaction.reaction)) map.set(reaction.reaction, { count: 0, iReacted: false })
    const entry = map.get(reaction.reaction)
    entry.count += 1
    if (reaction._iMine) entry.iReacted = true
  }
  return Array.from(map.entries()).map(([emoji, { count, iReacted }]) => ({ emoji, count, iReacted }))
}
