import React, { useState, useEffect, useCallback, useRef } from 'react'
import { createRoot } from 'react-dom/client'
import ConversationList from '../../components/messaging/ConversationList'
import ConversationThread from '../../components/messaging/ConversationThread'
import NewConversationModal from '../../components/messaging/NewConversationModal'

function getCsrf() {
  return document.querySelector('meta[name="csrf-token"]')?.content ?? ''
}

async function apiFetch(url, options = {}) {
  const isFormData = options.body instanceof FormData
  const headers = {
    'X-CSRF-TOKEN': getCsrf(),
    Accept: 'application/json',
    ...options.headers,
  }

  if (!isFormData) {
    headers['Content-Type'] = 'application/json'
  }

  const res = await fetch(url, {
    headers,
    ...options,
  })

  if (!res.ok) {
    const err = await res.json().catch(() => ({}))
    throw new Error(err.message ?? `HTTP ${res.status}`)
  }

  return res.json()
}

function relativeTime(iso) {
  if (!iso) return 'No activity yet'

  const diff = (Date.now() - new Date(iso).getTime()) / 1000
  if (diff < 60) return 'Just now'
  if (diff < 3600) return `${Math.floor(diff / 60)}m ago`
  if (diff < 86400) return `${Math.floor(diff / 3600)}h ago`
  if (diff < 604800) return `${Math.floor(diff / 86400)}d ago`

  return new Date(iso).toLocaleDateString(undefined, {
    month: 'short',
    day: 'numeric',
  })
}

function buildSearchPreview(item) {
  const body = (item?.body || '').trim()
  return body || '(attachment only)'
}

function MessagesPage({ userId, username, activeConversationId: initialId }) {
  const [conversations, setConversations] = useState([])
  const [loadingConvs, setLoadingConvs] = useState(true)
  const [activeId, setActiveId] = useState(initialId ?? null)
  const [realtimeEnabled, setRealtimeEnabled] = useState(false)
  const [showNewModal, setShowNewModal] = useState(false)
  const [searchQuery, setSearchQuery] = useState('')
  const [searchResults, setSearchResults] = useState([])
  const [searching, setSearching] = useState(false)
  const pollRef = useRef(null)

  const loadConversations = useCallback(async () => {
    try {
      const data = await apiFetch('/api/messages/conversations')
      setConversations(data.data ?? [])
    } catch (e) {
      console.error('Failed to load conversations', e)
    } finally {
      setLoadingConvs(false)
    }
  }, [])

  useEffect(() => {
    loadConversations()

    apiFetch('/api/messages/settings')
      .then((data) => setRealtimeEnabled(!!data?.realtime_enabled))
      .catch(() => setRealtimeEnabled(false))

    return () => {
      if (pollRef.current) clearInterval(pollRef.current)
    }
  }, [loadConversations])

  useEffect(() => {
    if (pollRef.current) {
      clearInterval(pollRef.current)
      pollRef.current = null
    }

    if (realtimeEnabled) {
      return undefined
    }

    pollRef.current = setInterval(loadConversations, 15000)

    return () => {
      if (pollRef.current) clearInterval(pollRef.current)
    }
  }, [loadConversations, realtimeEnabled])

  const handleSelectConversation = useCallback((id) => {
    setActiveId(id)
    history.replaceState(null, '', `/messages/${id}`)
  }, [])

  const handleConversationCreated = useCallback((conv) => {
    setShowNewModal(false)
    loadConversations()
    setActiveId(conv.id)
    history.replaceState(null, '', `/messages/${conv.id}`)
  }, [loadConversations])

  const handleMarkRead = useCallback((conversationId) => {
    setConversations((prev) => prev.map((conversation) => (
      conversation.id === conversationId
        ? { ...conversation, unread_count: 0 }
        : conversation
    )))
  }, [])

  useEffect(() => {
    let cancelled = false

    const run = async () => {
      const q = searchQuery.trim()
      if (q.length < 2) {
        setSearchResults([])
        setSearching(false)
        return
      }

      setSearching(true)

      try {
        const data = await apiFetch(`/api/messages/search?q=${encodeURIComponent(q)}`)
        if (!cancelled) {
          setSearchResults(data.data ?? [])
        }
      } catch {
        if (!cancelled) {
          setSearchResults([])
        }
      } finally {
        if (!cancelled) {
          setSearching(false)
        }
      }
    }

    const timer = setTimeout(run, 250)
    return () => {
      cancelled = true
      clearTimeout(timer)
    }
  }, [searchQuery])

  const openSearchResult = useCallback((item) => {
    if (!item?.conversation_id) return
    setActiveId(item.conversation_id)
    history.replaceState(null, '', `/messages/${item.conversation_id}?focus=${item.id}`)
  }, [])

  const activeConversation = conversations.find((conversation) => conversation.id === activeId) ?? null
  const unreadCount = conversations.reduce((sum, conversation) => sum + Number(conversation.unread_count || 0), 0)
  const pinnedCount = conversations.reduce((sum, conversation) => {
    const me = conversation.my_participant ?? conversation.all_participants?.find((participant) => participant.user_id === userId)
    return sum + (me?.is_pinned ? 1 : 0)
  }, 0)
  const archivedCount = conversations.reduce((sum, conversation) => {
    const me = conversation.my_participant ?? conversation.all_participants?.find((participant) => participant.user_id === userId)
    return sum + (me?.is_archived ? 1 : 0)
  }, 0)
  const activeSearch = searchQuery.trim().length >= 2
  const activeConversationLabel = activeConversation?.title
    || activeConversation?.all_participants?.find((participant) => participant.user_id !== userId)?.user?.username
    || 'Conversation'

  return (
    <div className="px-4 pb-16 pt-4 md:px-6 lg:px-8 lg:pt-6">
      <div className="grid gap-5 lg:items-start lg:grid-cols-[340px_minmax(0,1fr)] xl:grid-cols-[360px_minmax(0,1fr)] xl:gap-6">
        <aside className={`flex min-h-[calc(100vh-18rem)] flex-col overflow-hidden rounded-[30px] border border-white/[0.06] bg-[linear-gradient(180deg,rgba(10,16,26,0.96),rgba(7,11,18,0.92))] shadow-[0_20px_60px_rgba(0,0,0,0.28)] lg:sticky lg:top-6 lg:max-h-[calc(100vh-3rem)] ${activeId ? 'hidden lg:flex' : 'flex'}`}>
          <div className="border-b border-white/[0.06] p-5">
            <div className="flex items-start justify-between gap-4">
              <div>
                <p className="text-[11px] font-semibold uppercase tracking-[0.2em] text-white/35">Private inbox</p>
                <h2 className="mt-2 text-2xl font-semibold text-white">Messages</h2>
                <p className="mt-2 text-sm leading-6 text-white/50">Keep direct chats, group threads, and file drops in one focused workspace.</p>
              </div>
              <button
                onClick={() => setShowNewModal(true)}
                className="inline-flex h-11 items-center justify-center gap-2 rounded-full border border-sky-400/20 bg-sky-500/12 px-4 text-sm font-medium text-sky-200 transition hover:bg-sky-500/18"
                title="New message"
              >
                <i className="fa-solid fa-pen-to-square text-xs" />
                Compose
              </button>
            </div>

            <div className="mt-5 grid grid-cols-3 gap-2">
              <StatChip label="Unread" value={unreadCount} tone="sky" />
              <StatChip label="Pinned" value={pinnedCount} tone="amber" />
              <StatChip label="Archived" value={archivedCount} tone="slate" />
            </div>

            <div className="mt-4 flex flex-wrap gap-2 text-xs text-white/45">
              <span className={`inline-flex items-center gap-1.5 rounded-full border px-3 py-1 ${realtimeEnabled ? 'border-emerald-400/20 bg-emerald-500/10 text-emerald-200' : 'border-white/[0.08] bg-white/[0.04] text-white/55'}`}>
                <span className={`h-1.5 w-1.5 rounded-full ${realtimeEnabled ? 'bg-emerald-300' : 'bg-white/30'}`} />
                {realtimeEnabled ? 'Realtime active' : 'Polling every 15s'}
              </span>
              <span className="inline-flex items-center gap-1.5 rounded-full border border-white/[0.08] bg-white/[0.04] px-3 py-1 text-white/55">
                <i className="fa-solid fa-comments text-[10px]" />
                {conversations.length} conversations
              </span>
            </div>
          </div>

          <div className="border-b border-white/[0.06] p-4">
            <label className="mb-2 block text-[11px] font-semibold uppercase tracking-[0.18em] text-white/35">Search all messages</label>
            <div className="rounded-2xl border border-white/[0.08] bg-black/15 px-3 py-2.5 transition focus-within:border-sky-400/30 focus-within:bg-black/25">
              <div className="flex items-center gap-3">
                <i className="fa-solid fa-magnifying-glass text-xs text-white/30" />
                <input
                  type="search"
                  value={searchQuery}
                  onChange={(e) => setSearchQuery(e.target.value)}
                  placeholder="Find text, attachments, or senders…"
                  className="w-full bg-transparent text-sm text-white outline-none placeholder:text-white/25"
                />
              </div>
            </div>
            {searching ? <p className="mt-2 text-[11px] text-white/35">Searching across your inbox…</p> : null}
          </div>

          {activeSearch ? (
            <div className="border-b border-white/[0.06] px-3 py-3">
              <div className="mb-2 flex items-center justify-between px-2">
                <p className="text-[11px] font-semibold uppercase tracking-[0.18em] text-white/35">Search results</p>
                <span className="text-[11px] text-white/30">{searchResults.length}</span>
              </div>

              <div className="max-h-64 space-y-2 overflow-y-auto pr-1">
                {searchResults.length === 0 && !searching ? (
                  <div className="rounded-2xl border border-white/[0.06] bg-white/[0.025] px-4 py-4 text-sm text-white/40">
                    No results matched “{searchQuery.trim()}”.
                  </div>
                ) : null}

                {searchResults.map((item) => (
                  <button
                    key={`search-${item.id}`}
                    onClick={() => openSearchResult(item)}
                    className="block w-full rounded-2xl border border-white/[0.06] bg-white/[0.03] px-4 py-3 text-left transition hover:border-sky-400/20 hover:bg-sky-500/[0.08]"
                  >
                    <div className="flex items-center justify-between gap-3 text-[11px] text-white/35">
                      <span>@{item.sender?.username ?? 'unknown'}</span>
                      <span>{relativeTime(item.created_at)}</span>
                    </div>
                    <p className="mt-2 line-clamp-2 text-sm leading-6 text-white/78">{buildSearchPreview(item)}</p>
                  </button>
                ))}
              </div>
            </div>
          ) : null}

          <ConversationList
            conversations={conversations}
            loading={loadingConvs}
            activeId={activeId}
            currentUserId={userId}
            onSelect={handleSelectConversation}
          />
        </aside>

        <main className={`flex min-h-[calc(100vh-18rem)] min-w-0 flex-col overflow-hidden rounded-[30px] border border-white/[0.06] bg-[linear-gradient(180deg,rgba(10,16,26,0.96),rgba(7,11,18,0.92))] shadow-[0_20px_60px_rgba(0,0,0,0.28)] lg:h-[calc(100vh-3rem)] lg:max-h-[calc(100vh-3rem)] ${activeId ? 'flex' : 'hidden lg:flex'}`}>
          {activeId ? (
            <ConversationThread
              key={activeId}
              conversationId={activeId}
              conversation={activeConversation}
              realtimeEnabled={realtimeEnabled}
              currentUserId={userId}
              currentUsername={username}
              apiFetch={apiFetch}
              onBack={() => {
                setActiveId(null)
                history.replaceState(null, '', '/messages')
              }}
              onMarkRead={handleMarkRead}
              onConversationUpdated={loadConversations}
            />
          ) : (
            <div className="flex flex-1 items-center justify-center p-8">
              <div className="max-w-xl text-center">
                <div className="mx-auto flex h-18 w-18 items-center justify-center rounded-[26px] border border-white/[0.08] bg-white/[0.03] text-white/35 shadow-[0_18px_45px_rgba(0,0,0,0.22)]">
                  <i className="fa-solid fa-comments text-3xl" />
                </div>
                <h2 className="mt-6 text-3xl font-semibold text-white">Choose a conversation</h2>
                <p className="mt-3 text-sm leading-7 text-white/55">Jump back into a direct message, catch up on a group thread, or start a new conversation with creators and collaborators.</p>
                <div className="mt-6 flex flex-wrap items-center justify-center gap-2 text-sm text-white/55">
                  <span className="rounded-full border border-white/[0.08] bg-white/[0.04] px-4 py-2">Search your full message history</span>
                  <span className="rounded-full border border-white/[0.08] bg-white/[0.04] px-4 py-2">Share files inline</span>
                  <span className="rounded-full border border-white/[0.08] bg-white/[0.04] px-4 py-2">Track seen status</span>
                </div>
              </div>
            </div>
          )}
        </main>
      </div>

      {activeId ? (
        <div className="mt-4 rounded-2xl border border-white/[0.06] bg-white/[0.03] px-4 py-3 text-xs text-white/45 lg:hidden">
          Viewing <span className="font-medium text-white/75">{activeConversationLabel}</span>. Use the back button to return to your inbox list.
        </div>
      ) : null}

      {showNewModal ? (
        <NewConversationModal
          currentUserId={userId}
          apiFetch={apiFetch}
          onCreated={handleConversationCreated}
          onClose={() => setShowNewModal(false)}
        />
      ) : null}
    </div>
  )
}

function StatChip({ label, value, tone = 'sky' }) {
  const tones = {
    sky: 'border-sky-400/20 bg-sky-500/10 text-sky-200',
    amber: 'border-amber-400/20 bg-amber-500/10 text-amber-200',
    slate: 'border-white/[0.08] bg-white/[0.04] text-white/65',
  }

  return (
    <div className={`rounded-2xl border px-3 py-3 ${tones[tone] || tones.sky}`}>
      <p className="text-[10px] font-semibold uppercase tracking-[0.18em] opacity-70">{label}</p>
      <p className="mt-2 text-lg font-semibold">{Number(value || 0).toLocaleString()}</p>
    </div>
  )
}

const el = document.getElementById('messages-root')

if (el) {
  function parse(key, fallback = null) {
    try {
      return JSON.parse(el.dataset[key] ?? 'null') ?? fallback
    } catch {
      return fallback
    }
  }

  createRoot(el).render(
    <MessagesPage
      userId={parse('userId')}
      username={parse('username', '')}
      activeConversationId={parse('activeConversationId')}
    />,
  )
}

export default MessagesPage
