import Avatar from '@/components/ui/Avatar'
import Button from '@/components/ui/Button'
import Input from '@/components/ui/Input'
import Notification from '@/components/ui/Notification'
import Tooltip from '@/components/ui/Tooltip'
import { toast } from '@/components/ui'
import { AVATAR_URL } from '@/constants/app.constant'
import {
  getMessengerContacts,
  getMessengerMessages,
  MessengerAttachmentDto,
  MessengerContactDto,
  MessengerMessageDto,
  uploadMessengerAttachment,
} from '@/services/messenger.service'
import { messengerSignalR } from '@/services/messenger.signalr'
import { useStoreState } from '@/store'
import dayjs from 'dayjs'
import EmojiPicker, { EmojiClickData } from 'emoji-picker-react'
import { useEffect, useMemo, useRef, useState } from 'react'
import {
  FaArrowLeft,
  FaCompress,
  FaExpand,
  FaPaperclip,
  FaRegSmile,
  FaSearch,
  FaTimes,
  FaTrash,
} from 'react-icons/fa'
import { IoCheckmarkDone, IoChatbubbleEllipsesOutline, IoSend } from 'react-icons/io5'

const MAX_UPLOAD_SIZE = 10 * 1024 * 1024

const formatFileSize = (size: number) => {
  if (size < 1024 * 1024) return `${Math.max(1, Math.round(size / 1024))} KB`
  return `${(size / (1024 * 1024)).toFixed(1)} MB`
}

const canDeleteMessage = (message: MessengerMessageDto, userId: string) =>
  message.senderId === userId && dayjs().diff(dayjs(message.sentAt), 'minute', true) < 10

const MessengerWidget = () => {
  const auth = useStoreState((state) => state.auth)
  const tenantId = auth.user.tenantId || auth.tenant?.tenantId
  const fileInputRef = useRef<HTMLInputElement>(null)
  const messageInputRef = useRef<HTMLTextAreaElement>(null)
  const messagesEndRef = useRef<HTMLDivElement>(null)

  const [open, setOpen] = useState(false)
  const [contacts, setContacts] = useState<MessengerContactDto[]>([])
  const [selectedIds, setSelectedIds] = useState<string[]>([])
  const [messages, setMessages] = useState<MessengerMessageDto[]>([])
  const [text, setText] = useState('')
  const [filter, setFilter] = useState('')
  const [attachments, setAttachments] = useState<MessengerAttachmentDto[]>([])
  const [connected, setConnected] = useState(false)
  const [uploading, setUploading] = useState(false)
  const [showEmoji, setShowEmoji] = useState(false)
  const [multiSelect, setMultiSelect] = useState(false)
  const [maximized, setMaximized] = useState(false)
  const [unreadByContact, setUnreadByContact] = useState<Record<string, number>>({})

  const unread = useMemo(
    () => Object.values(unreadByContact).reduce((total, count) => total + count, 0),
    [unreadByContact],
  )

  useEffect(() => {
    if (!auth.session.signedIn) return

    const unsubscribeMessage = messengerSignalR.onMessage((message) => {
      setMessages((prev) => (prev.some((item) => item.id === message.id) ? prev : [...prev, message]))
      if (message.senderId !== auth.user.id && (!open || !selectedIds.includes(message.senderId))) {
        setUnreadByContact((current) => ({
          ...current,
          [message.senderId]: (current[message.senderId] || 0) + 1,
        }))
      }
    })
    const unsubscribeMessageDeleted = messengerSignalR.onMessageDeleted((message) => {
      setMessages((prev) => prev.filter((item) => item.id !== message.messageId))
    })
    const unsubscribeState = messengerSignalR.onStateChange(setConnected)
    messengerSignalR.start()

    return () => {
      unsubscribeMessage()
      unsubscribeMessageDeleted()
      unsubscribeState()
    }
  }, [auth.session.signedIn, auth.user.id, open, selectedIds])

  useEffect(() => {
    if (!auth.session.signedIn) {
      messengerSignalR.stop()
    }
  }, [auth.session.signedIn])

  useEffect(() => {
    if (!open) return
    getMessengerContacts(filter)
      .then((response) => setContacts(response.data))
      .catch(() => setContacts([]))
  }, [filter, open])

  useEffect(() => {
    messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })
  }, [messages, open])

  useEffect(() => {
    if (!open || selectedIds.length === 0) return

    const timer = window.setTimeout(() => {
      messageInputRef.current?.focus()
    }, 0)

    return () => window.clearTimeout(timer)
  }, [open, selectedIds])

  useEffect(() => {
    if (!open || selectedIds.length === 0) return

    getMessengerMessages({
      participantIds: selectedIds,
      maxResultCount: 50,
      sorting: 'sentAt desc',
    })
      .then((response) => setMessages(response.data))
      .catch(() => setMessages([]))
  }, [open, selectedIds])

  const selectedContacts = useMemo(
    () => contacts.filter((contact) => selectedIds.includes(contact.id)),
    [contacts, selectedIds],
  )

  const visibleMessages = useMemo(() => {
    if (selectedIds.length === 0) return []

    return messages.filter((message) => {
      const isOwn = message.senderId === auth.user.id
      const participants = new Set([message.senderId, ...message.recipientIds])
      return selectedIds.some((id) => participants.has(id)) && (isOwn || selectedIds.includes(message.senderId))
    })
  }, [auth.user.id, messages, selectedIds])

  const toggleContact = (id: string) => {
    setUnreadByContact((current) => {
      if (!current[id]) return current

      const next = { ...current }
      delete next[id]
      return next
    })

    if (!multiSelect) {
      setSelectedIds([id])
      return
    }

    setSelectedIds((prev) => (prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id]))
  }

  const toggleMultiSelect = () => {
    setMultiSelect((value) => {
      if (value) {
        setSelectedIds((prev) => prev.slice(0, 1))
      }
      return !value
    })
  }

  const closeWidget = () => {
    setOpen(false)
    setMaximized(false)
    setSelectedIds([])
    setMessages([])
    setText('')
    setAttachments([])
    setShowEmoji(false)
  }

  const handleFiles = async (files: FileList | null) => {
    if (!files?.length) return

    const nextFiles = Array.from(files)
    const tooLarge = nextFiles.find((file) => file.size > MAX_UPLOAD_SIZE)
    if (tooLarge) {
      toast.push(<Notification title="Dosya 10 MB sınırını aşamaz" type="warning" />, {
        placement: 'top-end',
      })
      return
    }

    setUploading(true)
    try {
      const uploaded = await Promise.all(
        nextFiles.map((file) => uploadMessengerAttachment(file).then((response) => response.data)),
      )
      setAttachments((prev) => [...prev, ...uploaded])
    } catch {
      toast.push(<Notification title="Dosya yüklenemedi" type="danger" />, { placement: 'top-end' })
    } finally {
      setUploading(false)
      if (fileInputRef.current) fileInputRef.current.value = ''
    }
  }

  const sendMessage = async () => {
    const trimmedText = text.trim()
    if (selectedIds.length === 0 || (!trimmedText && attachments.length === 0)) return

    try {
      await messengerSignalR.sendMessage({
        recipientIds: selectedIds,
        text: trimmedText,
        attachments,
      })
      setText('')
      setAttachments([])
      setShowEmoji(false)
      window.setTimeout(() => {
        messageInputRef.current?.focus()
      }, 0)
    } catch {
      toast.push(<Notification title="Mesaj gönderilemedi" type="danger" />, { placement: 'top-end' })
    }
  }

  const deleteMessage = async (messageId: string) => {
    if (!window.confirm('Mesaj silinsin mi?')) return

    try {
      await messengerSignalR.deleteMessage(messageId)
    } catch {
      toast.push(<Notification title="Mesaj silinemedi" type="danger" />, { placement: 'top-end' })
    }
  }

  const onEmojiClick = (emoji: EmojiClickData) => {
    setText((current) => `${current}${emoji.emoji}`)
  }

  if (!auth.session.signedIn) return null

  const panelClassName = maximized
    ? 'pointer-events-auto fixed inset-2 overflow-hidden rounded-lg border border-gray-200 bg-white shadow-2xl dark:border-gray-700 dark:bg-gray-800 sm:inset-4'
    : 'pointer-events-auto fixed inset-x-2 bottom-20 top-3 overflow-hidden rounded-lg border border-gray-200 bg-white shadow-2xl dark:border-gray-700 dark:bg-gray-800 sm:absolute sm:inset-auto sm:bottom-16 sm:right-0 sm:h-[min(70vh,640px)] sm:w-[min(78vw,800px)]'

  return (
    <div className="pointer-events-none fixed bottom-5 right-5 z-50 h-14 w-14">
      {open && (
        <div className={panelClassName}>
          <div className="flex h-full min-h-0">
            <aside
              className={`min-h-0 w-full shrink-0 flex-col border-gray-200 bg-gray-50 dark:border-gray-700 dark:bg-gray-900 sm:flex sm:w-72 sm:border-r ${
                selectedIds.length > 0 ? 'hidden' : 'flex'
              }`}
            >
              <div className="flex h-16 items-center justify-between border-b border-gray-200 px-4 dark:border-gray-700">
                <div className="flex min-w-0 items-center gap-3">
                  <Avatar size={36} shape="circle" src={auth.user.avatar || AVATAR_URL(auth.user.id, tenantId)} />
                  <div className="min-w-0">
                    <div className="truncate text-sm font-semibold text-gray-900 dark:text-gray-100">
                      {auth.user.name || auth.user.userName || 'Messenger'}
                    </div>
                    <div className="flex items-center gap-1 text-xs text-gray-500">
                      <span className={`h-2 w-2 rounded-full ${connected ? 'bg-emerald-500' : 'bg-gray-400'}`} />
                      {connected ? 'Bağlı' : 'Bağlanıyor'}
                    </div>
                  </div>
                </div>
                <div className="flex shrink-0 items-center gap-1 sm:hidden">
                  <Tooltip title={maximized ? 'Küçült' : 'Büyüt'}>
                    <Button
                      size="xs"
                      variant="plain"
                      icon={maximized ? <FaCompress /> : <FaExpand />}
                      onClick={() => setMaximized((value) => !value)}
                    />
                  </Tooltip>
                  <Button size="xs" variant="plain" icon={<FaTimes />} onClick={closeWidget} />
                </div>
              </div>

              <div className="space-y-2 p-3">
                <Input
                  size="sm"
                  value={filter}
                  prefix={<FaSearch />}
                  placeholder="Kişi ara"
                  onChange={(event) => setFilter(event.target.value)}
                />
                <Button
                  size="xs"
                  variant={multiSelect ? 'twoTone' : 'default'}
                  block
                  onClick={toggleMultiSelect}
                >
                  {multiSelect ? 'Çoklu seçim açık' : 'Çoklu seçim'}
                </Button>
              </div>

              <div className="min-h-0 flex-1 overflow-y-auto px-2 pb-2">
                {contacts.map((contact) => {
                  const active = selectedIds.includes(contact.id)
                  const contactUnread = unreadByContact[contact.id] || 0
                  return (
                    <button
                      key={contact.id}
                      type="button"
                      onClick={() => toggleContact(contact.id)}
                      className={`mb-1 flex w-full items-center gap-3 rounded-md px-2 py-2 text-left transition ${
                        active
                          ? 'bg-emerald-50 text-emerald-700 dark:bg-emerald-500/15 dark:text-emerald-100'
                          : 'hover:bg-white dark:hover:bg-gray-800'
                      }`}
                    >
                      <Avatar size={36} shape="circle" src={AVATAR_URL(contact.id, contact.tenantId || tenantId)} />
                      <span className="min-w-0 flex-1">
                        <span className="block truncate text-sm font-medium">{contact.fullName}</span>
                        <span className="block truncate text-xs text-gray-500">{contact.email || contact.userName}</span>
                      </span>
                      {contactUnread > 0 && (
                        <span className="shrink-0 rounded-full bg-red-500 px-2 py-0.5 text-xs font-semibold text-white">
                          {contactUnread > 99 ? '99+' : contactUnread}
                        </span>
                      )}
                      {active && contactUnread === 0 && <IoCheckmarkDone className="shrink-0 text-lg" />}
                    </button>
                  )
                })}
              </div>
            </aside>

            <main
              className={`min-w-0 flex-1 flex-col ${
                selectedIds.length === 0 ? 'hidden sm:flex' : 'flex'
              }`}
            >
              <div className="flex h-16 items-center justify-between border-b border-gray-200 px-4 dark:border-gray-700">
                <div className="flex min-w-0 items-center gap-3">
                  <Button
                    size="xs"
                    variant="plain"
                    icon={<FaArrowLeft />}
                    className="shrink-0 sm:hidden"
                    onClick={() => setSelectedIds([])}
                  />
                  {selectedContacts.length === 1 && (
                    <Avatar
                      size={36}
                      shape="circle"
                      src={AVATAR_URL(selectedContacts[0].id, selectedContacts[0].tenantId || tenantId)}
                    />
                  )}
                  {selectedContacts.length > 1 && (
                    <Avatar size={36} shape="circle" className="bg-emerald-100 text-emerald-700">
                      {selectedContacts.length}
                    </Avatar>
                  )}
                  <div className="min-w-0 flex-1">
                    <div className="truncate text-sm font-semibold text-gray-900 dark:text-gray-100">
                      {selectedContacts.length === 1
                        ? selectedContacts[0].fullName
                        : selectedContacts.length > 1
                          ? `${selectedContacts.length} kişi seçildi`
                          : 'Sohbet'}
                    </div>
                    <div className="truncate text-xs text-gray-500">
                      {selectedContacts.length === 1
                        ? selectedContacts[0].email || selectedContacts[0].userName
                        : selectedContacts.length > 1
                          ? 'Toplu mesaj'
                          : 'Mesaj göndermek için kişi seçin'}
                    </div>
                  </div>
                </div>
                <div className="flex shrink-0 items-center gap-1">
                  <Tooltip title={maximized ? 'Küçült' : 'Büyüt'}>
                    <Button
                      size="xs"
                      variant="plain"
                      icon={maximized ? <FaCompress /> : <FaExpand />}
                      onClick={() => setMaximized((value) => !value)}
                    />
                  </Tooltip>
                  <Button size="xs" variant="plain" icon={<FaTimes />} onClick={closeWidget} />
                </div>
              </div>

              <div className="flex-1 overflow-y-auto bg-white px-4 py-3 dark:bg-gray-800">
                {visibleMessages.length === 0 && (
                  <div className="flex h-full items-center justify-center text-sm text-gray-400">
                    Henüz mesaj yok
                  </div>
                )}

                {visibleMessages.map((message) => {
                  const own = message.senderId === auth.user.id
                  const deletable = canDeleteMessage(message, auth.user.id)
                  return (
                    <div key={message.id} className={`mb-3 flex ${own ? 'justify-end' : 'justify-start'}`}>
                      <div className={`group flex max-w-[76%] items-start gap-1.5 ${own ? 'flex-row-reverse' : ''}`}>
                        <div
                          className={`rounded-lg px-3 py-2 shadow-sm ${
                            own
                              ? 'bg-emerald-600 text-white'
                              : 'bg-gray-100 text-gray-900 dark:bg-gray-700 dark:text-gray-100'
                          }`}
                        >
                        <div className="mb-1 flex items-center gap-1.5 text-xs font-semibold">
                          <Avatar
                            size={20}
                            shape="circle"
                            src={
                              own
                                ? auth.user.avatar || AVATAR_URL(auth.user.id, tenantId)
                                : AVATAR_URL(message.senderId, message.tenantId || tenantId)
                            }
                          />
                          <span className="max-w-[160px] truncate">
                            {own ? auth.user.name || auth.user.userName || 'Ben' : message.senderName}
                          </span>
                        </div>
                        {message.text && <div className="whitespace-pre-wrap text-sm leading-5">{message.text}</div>}
                        {message.attachments.length > 0 && (
                          <div className="mt-2 space-y-1">
                            {message.attachments.map((file) => (
                              <a
                                key={file.savedFileName}
                                href={file.url}
                                target="_blank"
                                rel="noreferrer"
                                className={`block rounded-md px-2 py-1 text-xs ${
                                  own ? 'bg-emerald-700 text-white' : 'bg-white text-gray-700 dark:bg-gray-800 dark:text-gray-100'
                                }`}
                              >
                                <span className="block truncate">{file.fileName}</span>
                                <span className="opacity-75">{formatFileSize(file.fileSize)}</span>
                              </a>
                            ))}
                          </div>
                        )}
                        <div
                          className={`mt-1 flex items-center gap-2 text-[11px] ${
                            own ? 'justify-end text-emerald-100' : 'justify-start text-gray-500'
                          }`}
                        >
                          <span>{dayjs(message.sentAt).format('HH:mm')}</span>
                        </div>
                        </div>
                        {own && deletable && (
                          <button
                            type="button"
                            title="Mesaji sil"
                            className="mt-1 flex h-5 w-5 shrink-0 items-center justify-center rounded-full text-[10px] text-gray-400 opacity-0 transition hover:bg-red-500 hover:text-white group-hover:opacity-100 focus:opacity-100"
                            onClick={() => deleteMessage(message.id)}
                          >
                            <FaTrash />
                          </button>
                        )}
                      </div>
                    </div>
                  )
                })}
                <div ref={messagesEndRef} />
              </div>

              {selectedIds.length > 0 && attachments.length > 0 && (
                <div className="flex flex-wrap gap-2 border-t border-gray-200 px-4 py-2 dark:border-gray-700">
                  {attachments.map((file) => (
                    <span
                      key={file.savedFileName}
                      className="inline-flex max-w-[220px] items-center gap-2 rounded-md bg-gray-100 px-2 py-1 text-xs dark:bg-gray-700"
                    >
                      <span className="truncate">{file.fileName}</span>
                      <button
                        type="button"
                        onClick={() =>
                          setAttachments((prev) =>
                            prev.filter((item) => item.savedFileName !== file.savedFileName),
                          )
                        }
                      >
                        <FaTrash />
                      </button>
                    </span>
                  ))}
                </div>
              )}

              {selectedIds.length > 0 && (
                <div className="relative border-t border-gray-200 p-3 dark:border-gray-700">
                  {showEmoji && (
                    <div className="absolute bottom-16 left-2 z-10 sm:left-10">
                      <EmojiPicker
                        onEmojiClick={onEmojiClick}
                        width="min(320px, calc(100vw - 32px))"
                        height={380}
                      />
                    </div>
                  )}
                  <div className="flex min-h-[52px] items-center gap-2 rounded-md border border-gray-300 bg-white px-2 py-1.5 focus-within:border-emerald-500 focus-within:ring-1 focus-within:ring-emerald-500 dark:border-gray-600 dark:bg-gray-800">
                    <input
                      ref={fileInputRef}
                      type="file"
                      multiple
                      className="hidden"
                      onChange={(event) => handleFiles(event.target.files)}
                    />
                    <Tooltip title="Dosya ekle">
                      <Button
                        type="button"
                        size="sm"
                        variant="plain"
                        loading={uploading}
                        icon={<FaPaperclip />}
                        className="shrink-0"
                        onClick={() => fileInputRef.current?.click()}
                      />
                    </Tooltip>
                    <Tooltip title="Emoji">
                      <Button
                        type="button"
                        size="sm"
                        variant="plain"
                        icon={<FaRegSmile />}
                        className="shrink-0"
                        onClick={() => setShowEmoji((value) => !value)}
                      />
                    </Tooltip>
                    <textarea
                      ref={messageInputRef}
                      value={text}
                      placeholder="Mesaj yazın"
                      rows={1}
                      autoFocus
                      className="min-h-[36px] flex-1 resize-none border-0 bg-transparent px-2 py-2 text-sm text-gray-900 outline-none placeholder:text-gray-400 focus:ring-0 dark:text-gray-100"
                      onChange={(event) => setText(event.target.value)}
                      onKeyDown={(event) => {
                        if (event.key === 'Enter' && !event.shiftKey) {
                          event.preventDefault()
                          sendMessage()
                        }
                      }}
                    />
                    <Button
                      type="button"
                      size="sm"
                      variant="solid"
                      icon={<IoSend />}
                      className="shrink-0"
                      disabled={!text.trim() && attachments.length === 0}
                      onClick={sendMessage}
                    />
                  </div>
                </div>
              )}
            </main>
          </div>
        </div>
      )}

      <Tooltip title="Messenger">
        <button
          type="button"
          onClick={() => (open ? closeWidget() : setOpen(true))}
          className="pointer-events-auto relative flex h-12 w-12 items-center justify-center rounded-full bg-emerald-600 text-2xl text-white shadow-xl transition hover:bg-emerald-700"
        >
          <IoChatbubbleEllipsesOutline />
          {unread > 0 && (
            <span className="absolute -right-1 -top-1 flex min-h-[20px] min-w-[20px] items-center justify-center rounded-full bg-red-500 px-1.5 text-xs font-semibold leading-none text-white ring-2 ring-white dark:ring-gray-800">
              {unread > 99 ? '99+' : unread}
            </span>
          )}
        </button>
      </Tooltip>
    </div>
  )
}

export default MessengerWidget
