import { useEffect, useRef, useState, type ChangeEvent, type KeyboardEvent } from 'react'
import { AlertCircle, Send, SmilePlus, X } from 'lucide-react'
import type { ChatConnectionStatus, ChatMessageOut } from '@/hooks/useChat'
import { formatLocalTime } from '@/lib/localTime'
import { useModalDismiss } from '@/hooks/useModalDismiss'

/**
 * Небольшой собственный набор популярных эмодзи — вместо библиотеки-пикера на
 * сотни килобайт ради десятка кнопок в поповере. Ровно 30 штук (6×5 —
 * `.chat-emoji-popover` в room.css рассчитан на эту сетку без остатка;
 * добавляя/убирая эмодзи, держи кратность 5).
 */
const EMOJI_OPTIONS = [
  '😀', '😂', '😊', '😉', '😍', '🤔', '😅', '😢',
  '😮', '😎', '🙌', '👍', '👎', '👏', '🙏', '❤️',
  '🔥', '🎉', '✅', '❌', '⚠️', '💡', '👀', '🤝',
  '🐎', '🦾', '🚀', '🦞', '💯', '🤷‍♂️',
]

interface ChatPanelProps {
  messages: ChatMessageOut[]
  status: ChatConnectionStatus
  statusMessage: string | null
  onSend: (text: string) => void
  onClose: () => void
}

/**
 * Панель чата комнаты конференции (см. design/mockups/room.html, блок
 * `.chat-panel`). Всегда в развёрнутом виде рендерится только пока сама
 * панель открыта — сворачивание/разворачивание и счётчик непрочитанных
 * управляются на уровне RoomPage (WS-соединение живёт независимо от того,
 * открыта ли панель, — иначе при сворачивании терялась бы история).
 *
 * Textarea, а не `<input>` из макета — сознательное отступление ради
 * Enter/Shift+Enter (перенос строки), стили сохранены визуально идентичными
 * пилюле-полю из макета.
 */
export function ChatPanel({ messages, status, statusMessage, onSend, onClose }: ChatPanelProps) {
  const [draft, setDraft] = useState('')
  const listRef = useRef<HTMLDivElement>(null)
  const textareaRef = useRef<HTMLTextAreaElement>(null)

  // Автоскролл к последнему сообщению — только если пользователь и так был
  // внизу списка, чтобы не мешать чтению прокрученной вверх истории.
  useEffect(() => {
    const el = listRef.current
    if (!el) return
    const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight
    if (distanceFromBottom < 120) {
      el.scrollTop = el.scrollHeight
    }
  }, [messages])

  // Авторасширение textarea до 4 строк, дальше — внутренний скролл. Эффектом,
  // а не только в обработчике ввода, — так пересчёт срабатывает и после
  // программной вставки эмодзи, и после очистки поля отправкой.
  useEffect(() => {
    const el = textareaRef.current
    if (!el) return
    el.style.height = 'auto'
    el.style.height = `${Math.min(el.scrollHeight, 96)}px`
  }, [draft])

  function handleSend() {
    const text = draft.trim()
    if (!text || status !== 'open') return
    onSend(text)
    setDraft('')
  }

  function handleKeyDown(event: KeyboardEvent<HTMLTextAreaElement>) {
    if (event.key === 'Enter' && !event.shiftKey) {
      event.preventDefault()
      handleSend()
    }
  }

  function handleDraftChange(event: ChangeEvent<HTMLTextAreaElement>) {
    setDraft(event.target.value)
  }

  // Вставка эмодзи в позицию курсора, а не в конец поля, — ожидаемое поведение
  // при редактировании текста в середине.
  function insertEmoji(emoji: string) {
    const el = textareaRef.current
    if (!el) {
      setDraft((current) => current + emoji)
      return
    }
    const start = el.selectionStart ?? draft.length
    const end = el.selectionEnd ?? draft.length
    setDraft(draft.slice(0, start) + emoji + draft.slice(end))
    // value обновится реальным React-рендером только на следующий тик —
    // курсор возвращаем после него, иначе setSelectionRange встанет на
    // ещё старую (более короткую) строку.
    requestAnimationFrame(() => {
      const pos = start + emoji.length
      el.focus()
      el.setSelectionRange(pos, pos)
    })
  }

  return (
    <aside className="chat-panel">
      <div className="chat-head">
        <h2>Чат встречи</h2>
        <button type="button" aria-label="Свернуть чат" onClick={onClose}>
          <X className="lucide" aria-hidden="true" />
        </button>
      </div>

      {statusMessage && (
        <p className="chat-status-banner">
          <AlertCircle className="lucide" aria-hidden="true" /> {statusMessage}
        </p>
      )}

      <div className="chat-messages" ref={listRef}>
        {messages.length === 0 && status === 'open' && !statusMessage && (
          <p className="chat-empty">Сообщений пока нет — начните обсуждение</p>
        )}
        {messages.map((message) => (
          <div className="msg" key={message.id}>
            <div className="msg-meta">
              <span className="msg-author">
                {message.author_name}
                {message.is_guest && <span className="msg-guest-badge">гость</span>}
              </span>
              <span className="msg-time">{formatLocalTime(message.created_at)}</span>
            </div>
            <div className="msg-bubble">{message.text}</div>
          </div>
        ))}
      </div>

      <form
        className="chat-input-row"
        onSubmit={(event) => {
          event.preventDefault()
          handleSend()
        }}
      >
        <EmojiPickerButton onSelect={insertEmoji} disabled={status !== 'open'} />
        <textarea
          ref={textareaRef}
          rows={1}
          placeholder="Написать сообщение…"
          value={draft}
          onChange={handleDraftChange}
          onKeyDown={handleKeyDown}
          disabled={status !== 'open'}
          maxLength={2000}
        />
        <button type="submit" aria-label="Отправить" disabled={!draft.trim() || status !== 'open'}>
          <Send className="lucide" aria-hidden="true" />
        </button>
      </form>
    </aside>
  )
}

interface EmojiPickerButtonProps {
  onSelect: (emoji: string) => void
  disabled: boolean
}

/**
 * Кнопка с поповером выбора эмодзи слева от поля ввода. Поповер открывается
 * ВВЕРХ от кнопки (как `.tb-menu` тулбара) — на мобильном чат-панель занята
 * полем ввода снизу, а место над тулбаром свободно, так поповер никогда не
 * перекрывает textarea.
 */
function EmojiPickerButton({ onSelect, disabled }: EmojiPickerButtonProps) {
  const [open, setOpen] = useState(false)
  const wrapRef = useRef<HTMLDivElement>(null)

  // Закрытие по клику вне — тем же паттерном, что меню «Вид» (StageViewMenu):
  // слушатель на document, пока поповер открыт.
  useEffect(() => {
    if (!open) return
    function handlePointerDown(event: MouseEvent) {
      if (wrapRef.current && !wrapRef.current.contains(event.target as Node)) {
        setOpen(false)
      }
    }
    document.addEventListener('mousedown', handlePointerDown)
    return () => document.removeEventListener('mousedown', handlePointerDown)
  }, [open])

  return (
    <div className="chat-emoji-wrap" ref={wrapRef}>
      <button
        type="button"
        className={`chat-emoji-trigger${open ? ' is-open' : ''}`}
        aria-label="Вставить эмодзи"
        aria-expanded={open}
        aria-haspopup="dialog"
        disabled={disabled}
        onClick={() => setOpen((v) => !v)}
      >
        <SmilePlus className="lucide" aria-hidden="true" />
      </button>
      {open && (
        <EmojiPopover
          onSelect={(emoji) => {
            onSelect(emoji)
            setOpen(false)
          }}
          onClose={() => setOpen(false)}
        />
      )}
    </div>
  )
}

interface EmojiPopoverProps {
  onSelect: (emoji: string) => void
  onClose: () => void
}

/** Отдельный компонент — чтобы `useModalDismiss` (Escape + возврат фокуса) жил ровно то время, пока поповер открыт. */
function EmojiPopover({ onSelect, onClose }: EmojiPopoverProps) {
  useModalDismiss(onClose)

  return (
    <div className="chat-emoji-popover" role="dialog" aria-label="Выбор эмодзи">
      {EMOJI_OPTIONS.map((emoji) => (
        <button key={emoji} type="button" className="chat-emoji-option" onClick={() => onSelect(emoji)}>
          {emoji}
        </button>
      ))}
    </div>
  )
}
