import { useQuery, useInfiniteQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { useState, useEffect, useRef, useCallback, useMemo } from 'react'
import { useParams, useNavigate } from 'react-router-dom'
import { useBreadcrumb } from '../../hooks/useBreadcrumb'
import { breadcrumbConfig } from '../../config/breadcrumbConfig'
import {
  MessageCircle,
  Search,
  RefreshCw,
  Loader2,
  Image as ImageIcon,
  Video,
  Play,
  ChevronUp,
  ChevronLeft,
  Lock,
  DollarSign,
  User,
} from 'lucide-react'
import { api, PaidContentMessage, PaidContentAttachment, PaidContentPost } from '../../lib/api'
import { formatRelativeTime, formatPlatformName, THUMB_CACHE_V } from '../../lib/utils'
import BundleLightbox from '../../components/paid-content/BundleLightbox'

export default function Messages() {
  useBreadcrumb(breadcrumbConfig['/paid-content/messages'])

  const { creatorId } = useParams<{ creatorId: string }>()
  const navigate = useNavigate()
  const queryClient = useQueryClient()
  const [search, setSearch] = useState('')
  const [selectedCreatorId, setSelectedCreatorId] = useState<number | null>(
    creatorId ? parseInt(creatorId) : null
  )
  const messagesEndRef = useRef<HTMLDivElement>(null)
  const messagesContainerRef = useRef<HTMLDivElement>(null)
  const [lightboxOpen, setLightboxOpen] = useState(false)
  const [lightboxAttachments, setLightboxAttachments] = useState<PaidContentAttachment[]>([])
  const [lightboxIndex, setLightboxIndex] = useState(0)
  const [lightboxPost, setLightboxPost] = useState<PaidContentPost | null>(null)
  // Mobile: track whether to show chat thread (true) or conversation list (false)
  const [showMobileChat, setShowMobileChat] = useState(!!creatorId)

  // Update URL when creator is selected
  useEffect(() => {
    if (selectedCreatorId && !creatorId) {
      navigate(`/paid-content/messages/${selectedCreatorId}`, { replace: true })
    }
  }, [selectedCreatorId, creatorId, navigate])

  // Conversations list
  const { data: conversations = [], isLoading: loadingConversations } = useQuery({
    queryKey: ['paid-content-conversations', search],
    queryFn: () => api.paidContent.getConversations({ search: search || undefined }),
  })

  // Auto-select most recent conversation when none is selected (desktop only)
  useEffect(() => {
    if (!selectedCreatorId && conversations.length > 0) {
      const first = conversations[0].creator_id
      setSelectedCreatorId(first)
      navigate(`/paid-content/messages/${first}`, { replace: true })
    }
  }, [conversations]) // eslint-disable-line react-hooks/exhaustive-deps

  // Messages for selected conversation
  const {
    data: messagesData,
    fetchNextPage,
    hasNextPage,
    isFetchingNextPage,
    isLoading: loadingMessages,
  } = useInfiniteQuery({
    queryKey: ['paid-content-messages', selectedCreatorId],
    queryFn: ({ pageParam }) =>
      api.paidContent.getMessages(selectedCreatorId!, {
        before: pageParam as string | undefined,
        limit: 50,
      }),
    getNextPageParam: (lastPage) => {
      const msgs = lastPage.messages
      if (msgs.length < 50) return undefined
      return msgs[msgs.length - 1]?.sent_at
    },
    initialPageParam: undefined as string | undefined,
    enabled: !!selectedCreatorId,
  })

  // Flatten and reverse messages (API returns newest first, we want oldest first)
  const allMessages = (messagesData?.pages ?? [])
    .flatMap((page) => page.messages)
    .reverse()

  const totalMessages = messagesData?.pages?.[0]?.total ?? 0

  // Find the first unread message from creator
  const firstUnreadId = useMemo(() => {
    const unread = allMessages.find((m) => m.is_read === 0 && m.is_from_creator === 1)
    return unread?.id ?? null
  }, [allMessages])

  // Scroll to first unread message, or bottom if all read
  const scrolledForCreator = useRef<number | null>(null)
  useEffect(() => {
    if (allMessages.length > 0 && !isFetchingNextPage && selectedCreatorId !== scrolledForCreator.current) {
      scrolledForCreator.current = selectedCreatorId
      if (firstUnreadId) {
        // Small delay to let DOM render
        requestAnimationFrame(() => {
          const el = document.getElementById(`msg-${firstUnreadId}`)
          if (el) {
            el.scrollIntoView({ behavior: 'auto', block: 'center' })
            return
          }
          messagesEndRef.current?.scrollIntoView({ behavior: 'auto' })
        })
      } else {
        messagesEndRef.current?.scrollIntoView({ behavior: 'auto' })
      }
    }
  }, [selectedCreatorId, allMessages.length > 0, isFetchingNextPage]) // eslint-disable-line react-hooks/exhaustive-deps

  // Mark messages as read when they scroll into view (IntersectionObserver)
  const pendingMarkRead = useRef<Set<number>>(new Set())
  const markReadTimer = useRef<ReturnType<typeof setTimeout> | null>(null)

  const flushMarkRead = useCallback(() => {
    if (!selectedCreatorId || pendingMarkRead.current.size === 0) return
    const ids = Array.from(pendingMarkRead.current)
    pendingMarkRead.current.clear()
    api.paidContent.markMessagesRead(selectedCreatorId, ids).then(() => {
      queryClient.invalidateQueries({ queryKey: ['paid-content-conversations'] })
    }).catch(() => {})
  }, [selectedCreatorId, queryClient])

  const onMessageVisible = useCallback((messageId: number) => {
    pendingMarkRead.current.add(messageId)
    if (markReadTimer.current) clearTimeout(markReadTimer.current)
    markReadTimer.current = setTimeout(flushMarkRead, 500)
  }, [flushMarkRead])

  // Flush on unmount or conversation change
  useEffect(() => {
    return () => {
      if (markReadTimer.current) clearTimeout(markReadTimer.current)
      flushMarkRead()
    }
  }, [selectedCreatorId]) // eslint-disable-line react-hooks/exhaustive-deps

  // Sync messages mutation
  const syncMutation = useMutation({
    mutationFn: (cId: number) => api.paidContent.syncMessages(cId),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['paid-content-conversations'] })
      queryClient.invalidateQueries({ queryKey: ['paid-content-messages', selectedCreatorId] })
    },
  })

  const handleSelectConversation = (cId: number) => {
    setSelectedCreatorId(cId)
    setShowMobileChat(true)
    navigate(`/paid-content/messages/${cId}`, { replace: true })
  }

  const handleBackToList = () => {
    setShowMobileChat(false)
  }

  const handleLoadMore = useCallback(() => {
    if (hasNextPage && !isFetchingNextPage) {
      fetchNextPage()
    }
  }, [hasNextPage, isFetchingNextPage, fetchNextPage])

  const openLightbox = (attachments: PaidContentAttachment[], index: number, message?: PaidContentMessage) => {
    setLightboxAttachments(attachments)
    setLightboxIndex(index)
    // Build a fake post object for BundleLightbox from conversation + message data
    const conv = selectedConversation
    setLightboxPost({
      id: message?.id ?? 0,
      creator_id: conv?.creator_id ?? 0,
      post_id: message?.message_id ?? '',
      title: null,
      content: message?.text ?? null,
      published_at: message?.sent_at ?? null,
      added_at: message?.created_at ?? null,
      has_attachments: attachments.length > 0 ? 1 : 0,
      attachment_count: attachments.length,
      downloaded: 0,
      download_date: null,
      is_favorited: 0,
      is_viewed: 0,
      is_pinned: 0,
      pinned_at: null,
      username: conv?.username ?? '',
      platform: conv?.platform ?? '',
      service_id: conv?.service_id ?? '',
      display_name: conv?.display_name ?? null,
      profile_image_url: conv?.profile_image_url ?? null,
      identity_id: null,
      attachments,
    } as PaidContentPost)
    setLightboxOpen(true)
  }

  const selectedConversation = conversations.find((c) => c.creator_id === selectedCreatorId)

  // ---- Conversation List Panel ----
  const conversationList = (
    <div className={`flex flex-col bg-card h-full
      ${/* Desktop: fixed-width sidebar, always visible */''}
      max-md:w-full md:w-80 md:flex-shrink-0 md:border-r md:border-border
      ${/* Mobile: hidden when chat is open */''}
      ${showMobileChat ? 'max-md:hidden' : ''}
    `}>
      <div className="p-3 border-b border-border">
        <div className="relative">
          <Search className="absolute left-2.5 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" />
          <input
            type="text"
            placeholder="Search conversations..."
            value={search}
            onChange={(e) => setSearch(e.target.value)}
            className="w-full pl-8 pr-3 py-1.5 text-sm rounded-md border border-input bg-background"
          />
        </div>
      </div>

      <div className="flex-1 overflow-y-auto">
        {loadingConversations ? (
          <div className="flex justify-center py-8">
            <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />
          </div>
        ) : conversations.length === 0 ? (
          <div className="text-center py-8 text-muted-foreground text-sm">
            No conversations yet. Sync a creator to fetch messages.
          </div>
        ) : (
          conversations.map((conv) => (
            <button
              key={conv.creator_id}
              onClick={() => handleSelectConversation(conv.creator_id)}
              className={`w-full text-left px-3 py-2.5 border-b border-border/50 hover:bg-accent/50 transition-colors ${
                selectedCreatorId === conv.creator_id ? 'bg-violet-500/10 border-l-2 border-l-violet-500' : ''
              }`}
            >
              <div className="flex items-center gap-2.5">
                {conv.profile_image_url ? (
                  <img
                    src={conv.profile_image_url.startsWith('/api/') ? conv.profile_image_url : `/api/paid-content/proxy/image?url=${encodeURIComponent(conv.profile_image_url)}`}
                    alt=""
                    className="w-9 h-9 rounded-full object-cover flex-shrink-0"
                    onError={(e) => {
                      ;(e.target as HTMLImageElement).style.display = 'none'
                    }}
                  />
                ) : (
                  <div className="w-9 h-9 rounded-full bg-muted flex items-center justify-center flex-shrink-0">
                    <User className="w-4 h-4 text-muted-foreground" />
                  </div>
                )}
                <div className="flex-1 min-w-0">
                  <div className="flex items-center justify-between">
                    <span className="font-medium text-sm truncate">
                      {conv.display_name || conv.username}
                    </span>
                    {conv.last_message_at && (
                      <span className="text-[10px] text-muted-foreground flex-shrink-0 ml-1">
                        {formatRelativeTime(conv.last_message_at)}
                      </span>
                    )}
                  </div>
                  <div className="flex items-center justify-between mt-0.5">
                    <p className="text-xs text-muted-foreground truncate">
                      {conv.last_message_from_creator
                        ? conv.last_message_text || 'Sent media'
                        : `You: ${conv.last_message_text || 'Sent media'}`}
                    </p>
                    {conv.unread_count > 0 && (
                      <span className="ml-1 flex-shrink-0 bg-primary text-primary-foreground text-[10px] font-bold px-1.5 py-0.5 rounded-full">
                        {conv.unread_count}
                      </span>
                    )}
                  </div>
                  <div className="flex items-center gap-1 mt-0.5">
                    <span className="text-[10px] text-muted-foreground">
                      {formatPlatformName(conv.platform)}
                    </span>
                    <span className="text-[10px] text-muted-foreground">
                      &middot; {conv.message_count} msgs
                    </span>
                  </div>
                </div>
              </div>
            </button>
          ))
        )}
      </div>
    </div>
  )

  // ---- Chat Thread Panel ----
  const chatThread = (
    <div className={`flex-1 flex flex-col min-w-0 h-full
      ${/* Mobile: hidden when list is showing */''}
      ${!showMobileChat ? 'max-md:hidden' : ''}
    `}>
      {!selectedCreatorId ? (
        <div className="flex-1 flex items-center justify-center text-muted-foreground">
          <div className="text-center">
            <MessageCircle className="w-12 h-12 mx-auto mb-3 opacity-30" />
            <p className="text-sm">Select a conversation to view messages</p>
          </div>
        </div>
      ) : (
        <>
          {/* Chat header */}
          <div className="flex items-center justify-between px-3 sm:px-4 py-2.5 border-b border-border bg-card">
            <div className="flex items-center gap-2">
              {/* Back button - mobile only */}
              <button
                onClick={handleBackToList}
                className="md:hidden p-1 -ml-1 rounded-md hover:bg-accent transition-colors"
              >
                <ChevronLeft className="w-5 h-5" />
              </button>
              {selectedConversation?.profile_image_url ? (
                <img
                  src={selectedConversation.profile_image_url.startsWith('/api/') ? selectedConversation.profile_image_url : `/api/paid-content/proxy/image?url=${encodeURIComponent(selectedConversation.profile_image_url)}`}
                  alt=""
                  className="w-8 h-8 rounded-full object-cover"
                  onError={(e) => {
                    ;(e.target as HTMLImageElement).style.display = 'none'
                  }}
                />
              ) : (
                <div className="w-8 h-8 rounded-full bg-muted flex items-center justify-center">
                  <User className="w-4 h-4 text-muted-foreground" />
                </div>
              )}
              <div>
                <p className="font-medium text-sm">
                  {selectedConversation?.display_name || selectedConversation?.username}
                </p>
                <p className="text-[10px] text-muted-foreground">
                  {totalMessages} messages &middot; {formatPlatformName(selectedConversation?.platform)}
                </p>
              </div>
            </div>
            <button
              onClick={() => syncMutation.mutate(selectedCreatorId)}
              disabled={syncMutation.isPending}
              className="flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md border border-input hover:bg-accent transition-colors disabled:opacity-50"
            >
              <RefreshCw className={`w-3.5 h-3.5 ${syncMutation.isPending ? 'animate-spin' : ''}`} />
              <span className="hidden sm:inline">Sync</span>
            </button>
          </div>

          {/* Messages area */}
          <div ref={messagesContainerRef} className="flex-1 overflow-y-auto px-3 sm:px-4 py-3 space-y-2">
            {/* Load more button */}
            {hasNextPage && (
              <div className="text-center py-2">
                <button
                  onClick={handleLoadMore}
                  disabled={isFetchingNextPage}
                  className="inline-flex items-center gap-1.5 px-3 py-1 text-xs rounded-md border border-input hover:bg-accent transition-colors disabled:opacity-50"
                >
                  {isFetchingNextPage ? (
                    <Loader2 className="w-3 h-3 animate-spin" />
                  ) : (
                    <ChevronUp className="w-3 h-3" />
                  )}
                  Load older messages
                </button>
              </div>
            )}

            {loadingMessages ? (
              <div className="flex justify-center py-12">
                <Loader2 className="w-6 h-6 animate-spin text-muted-foreground" />
              </div>
            ) : allMessages.length === 0 ? (
              <div className="text-center py-12 text-muted-foreground text-sm">
                No messages yet
              </div>
            ) : (
              allMessages.map((msg) => (
                <MessageBubble
                  key={msg.id}
                  message={msg}
                  onOpenLightbox={openLightbox}
                  onVisible={msg.is_read === 0 && msg.is_from_creator === 1 ? onMessageVisible : undefined}
                />
              ))
            )}
            <div ref={messagesEndRef} />
          </div>
        </>
      )}
    </div>
  )

  return (
    <div className="space-y-2 sm:space-y-4">
      {/* Header - hidden on mobile when viewing a chat */}
      <div className={`flex items-center justify-between ${showMobileChat ? 'max-md:hidden' : ''}`}>
        <div>
          <h1 className="text-2xl sm:text-3xl font-bold flex items-center gap-2 sm:gap-3">
            <MessageCircle className="w-8 h-8 text-violet-500" />
            Messages
          </h1>
          <p className="text-slate-600 dark:text-slate-400 mt-1 hidden sm:block">
            View chat messages from creators
          </p>
        </div>
      </div>

      {/* Chat Layout */}
      <div className="flex h-[calc(100vh-8rem)] sm:h-[calc(100vh-10rem)] overflow-hidden rounded-xl border border-border">
        {conversationList}
        {chatThread}
      </div>

      {/* Lightbox */}
      {lightboxOpen && lightboxPost && lightboxAttachments.length > 0 && (
        <BundleLightbox
          post={lightboxPost}
          attachments={lightboxAttachments}
          currentIndex={lightboxIndex}
          wasPlaying={true}
          onClose={() => setLightboxOpen(false)}
          onNavigate={setLightboxIndex}
        />
      )}
    </div>
  )
}

// ============ Message Bubble Component ============

function MessageBubble({
  message,
  onOpenLightbox,
  onVisible,
}: {
  message: PaidContentMessage
  onOpenLightbox: (attachments: PaidContentAttachment[], index: number, message: PaidContentMessage) => void
  onVisible?: (messageId: number) => void
}) {
  const isCreator = message.is_from_creator === 1
  const viewableAttachments = message.attachments.filter((a) => a.status === 'completed' || a.status === 'duplicate')
  const hasLockedContent = message.price && !message.is_purchased && message.is_free === 0
  const bubbleRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    if (!onVisible || !bubbleRef.current) return
    const observer = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          onVisible(message.id)
          observer.disconnect()
        }
      },
      { threshold: 0.5 }
    )
    observer.observe(bubbleRef.current)
    return () => observer.disconnect()
  }, [onVisible, message.id])

  return (
    <div id={`msg-${message.id}`} ref={bubbleRef} className={`flex ${isCreator ? 'justify-start' : 'justify-end'}`}>
      <div
        className={`max-w-[85%] sm:max-w-[75%] rounded-xl px-3 py-2 ${
          isCreator
            ? 'bg-secondary text-secondary-foreground rounded-tl-sm'
            : 'bg-primary text-primary-foreground rounded-tr-sm'
        }`}
      >
        {/* PPV badge */}
        {hasLockedContent && (
          <div className="flex items-center gap-1 mb-1">
            <Lock className="w-3 h-3" />
            <span className="text-[10px] font-medium">
              PPV {message.price ? `$${message.price.toFixed(2)}` : ''}
            </span>
          </div>
        )}

        {/* Tip badge */}
        {message.is_tip === 1 && (
          <div className="flex items-center gap-1 mb-1">
            <DollarSign className="w-3 h-3" />
            <span className="text-[10px] font-medium">
              Tip {message.tip_amount ? `$${message.tip_amount.toFixed(2)}` : ''}
            </span>
          </div>
        )}

        {/* Message text */}
        {message.text && (
          <p className="text-sm whitespace-pre-wrap break-words">{message.text}</p>
        )}

        {/* Media attachments - post-style grid */}
        {message.attachments.length > 0 && (() => {
          const completed = message.attachments.filter((a) => a.status === 'completed' || a.status === 'duplicate')
          const pending = message.attachments.filter((a) => a.status !== 'completed' && a.status !== 'duplicate')
          return (
            <div className={message.text ? 'mt-2' : ''}>
              {/* Completed media grid */}
              {completed.length > 0 && (() => {
                const isSingle = completed.length === 1
                // For single items, use the attachment's own aspect ratio
                // For multi-item grids, compute a unified ratio from the average so rows align
                const ratios = completed
                  .filter((a) => a.width && a.height)
                  .map((a) => a.width! / a.height!)
                const avgRatio = ratios.length > 0
                  ? ratios.reduce((s, r) => s + r, 0) / ratios.length
                  : 16 / 9
                // Clamp between 3:4 portrait and 16:9 landscape
                const gridRatio = Math.max(3 / 4, Math.min(16 / 9, avgRatio))

                return (
                  <div className={`grid gap-1 ${isSingle ? 'grid-cols-1' : 'grid-cols-2'}`}>
                    {completed.map((att) => {
                      const isVideo = att.file_type === 'video'
                      const thumbUrl = `/api/paid-content/files/thumbnail/${att.id}?size=large&${att.file_hash ? `v=${att.file_hash.slice(0, 8)}` : THUMB_CACHE_V}`
                      const hasOwnRatio = att.width && att.height
                      // Single: use own ratio; multi: use unified grid ratio
                      const ratio = isSingle
                        ? (hasOwnRatio ? `${att.width} / ${att.height}` : (isVideo ? '16 / 9' : '1'))
                        : `${gridRatio}`
                      return (
                        <button
                          key={att.id}
                          type="button"
                          className="relative rounded-lg overflow-hidden bg-black cursor-pointer hover:opacity-90 transition-opacity"
                          style={{ aspectRatio: ratio }}
                          onClick={() => {
                            const idx = viewableAttachments.findIndex((a) => a.id === att.id)
                            onOpenLightbox(viewableAttachments, idx >= 0 ? idx : 0, message)
                          }}
                        >
                          <img
                            src={thumbUrl}
                            alt=""
                            className={`w-full h-full ${isSingle ? 'object-contain' : 'object-cover'}`}
                            loading="lazy"
                          />
                          {isVideo && (
                            <div className="absolute inset-0 flex items-center justify-center">
                              <div className="w-10 h-10 rounded-full bg-black/50 flex items-center justify-center">
                                <Play className="w-5 h-5 text-white ml-0.5" fill="white" />
                              </div>
                            </div>
                          )}
                        </button>
                      )
                    })}
                  </div>
                )
              })()}
              {/* Pending/unavailable attachments */}
              {pending.length > 0 && (
                <div className={`${completed.length > 0 ? 'mt-1' : ''} flex flex-wrap gap-1`}>
                  {pending.map((att) => (
                    <div
                      key={att.id}
                      className="relative w-16 h-16 rounded-md overflow-hidden bg-muted/30 flex flex-col items-center justify-center gap-0.5"
                    >
                      {att.file_type === 'video' ? (
                        <Video className="w-4 h-4 text-muted-foreground/50" />
                      ) : (
                        <ImageIcon className="w-4 h-4 text-muted-foreground/50" />
                      )}
                      <span className="text-[8px] text-muted-foreground/40">
                        {att.status === 'pending' ? 'Pending' : att.status}
                      </span>
                    </div>
                  ))}
                </div>
              )}
            </div>
          )
        })()}

        {/* Timestamp */}
        <p
          className={`text-[10px] mt-1 ${
            isCreator ? 'text-muted-foreground/70' : 'text-primary-foreground/70'
          }`}
        >
          {message.sent_at
            ? new Date(message.sent_at).toLocaleString(undefined, {
                month: 'short',
                day: 'numeric',
                hour: '2-digit',
                minute: '2-digit',
              })
            : ''}
        </p>
      </div>
    </div>
  )
}

