'use client';

import { useEffect, useRef, useState, useCallback } from 'react';
import { ArrowLeft, Send, ShieldAlert } from 'lucide-react';
import Link from 'next/link';
import { useAuth } from '@/contexts/AuthContext';
import { useSocket, SOCKET_EVENTS } from '@/contexts/SocketContext';
import { useMessages } from '@/contexts/MessagesContext';
import { api } from '@/lib/api';
import {
  ChatMessage,
  ChatUser,
  formatMessageDayLabel,
  formatMessageTime,
  isSameMessageDay,
} from '@/lib/messages';
import { isJobContextMetadata, consumePendingJobMessage, type JobContextMetadata } from '@/lib/jobContextMessage';
import { JobContextCard } from '@/components/messages/JobContextCard';
import { Button } from '@/components/ui/button';
import { UserAvatar } from '@/components/ui/UserAvatar';
import { cn } from '@/lib/utils';
import { isRecentlyActive } from '@/lib/lastActive';

interface ChatThreadProps {
  conversationId: string;
  relatedConversationIds?: string[];
  backHref: string;
  title?: string;
  subtitle?: string;
  role: 'customer' | 'worker';
  jobContext?: JobContextMetadata | null;
  peer?: ChatUser | null;
  peerProfileHref?: string | null;
}

export function ChatThread({
  conversationId,
  relatedConversationIds = [],
  backHref,
  title,
  subtitle,
  role,
  jobContext,
  peer,
  peerProfileHref,
}: ChatThreadProps) {
  const { user } = useAuth();
  const { socket, isConnected } = useSocket();
  const { refreshUnreadCount } = useMessages();
  const [messages, setMessages] = useState<ChatMessage[]>([]);
  const [input, setInput] = useState('');
  const [loading, setLoading] = useState(true);
  const [sending, setSending] = useState(false);
  const [typingUser, setTypingUser] = useState<string | null>(null);
  const messagesEndRef = useRef<HTMLDivElement>(null);
  const messagesContainerRef = useRef<HTMLDivElement>(null);
  const typingTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const pendingMessageSentRef = useRef(false);
  const textareaRef = useRef<HTMLTextAreaElement>(null);

  const customerProfile = user?.customerProfile as { isVerified?: boolean } | undefined;
  const messagingLocked =
    role === 'customer' && user?.role === 'CUSTOMER' && customerProfile?.isVerified !== true;

  const scrollToBottom = useCallback((smooth = true) => {
    const container = messagesContainerRef.current;
    if (container) {
      container.scrollTo({
        top: container.scrollHeight,
        behavior: smooth ? 'smooth' : 'auto',
      });
    }
  }, []);

  const loadMessages = useCallback(async () => {
    try {
      const res = await api<{ data: ChatMessage[] }>(
        `/messages/${conversationId}/messages?limit=100`
      );
      setMessages(res.data);
      await api(`/messages/${conversationId}/read`, { method: 'PATCH' });
      refreshUnreadCount();
    } catch (err) {
      console.error(err);
    } finally {
      setLoading(false);
    }
  }, [conversationId, refreshUnreadCount]);

  useEffect(() => {
    setLoading(true);
    setMessages([]);
    pendingMessageSentRef.current = false;
    loadMessages();
  }, [loadMessages]);

  useEffect(() => {
    if (!loading) scrollToBottom(false);
  }, [loading, scrollToBottom]);

  useEffect(() => {
    scrollToBottom();
  }, [messages, typingUser, scrollToBottom]);

  useEffect(() => {
    if (!socket || !conversationId) return;

    const roomIds =
      relatedConversationIds.length > 0 ? relatedConversationIds : [conversationId];
    for (const roomId of roomIds) {
      socket.emit('join-conversation', roomId);
    }

    const onMessage = (message: ChatMessage & { conversationId?: string }) => {
      const incomingConversationId = message.conversationId;
      if (incomingConversationId && !roomIds.includes(incomingConversationId)) return;
      setMessages((prev) => {
        if (prev.some((m) => m.id === message.id)) return prev;
        return [...prev, { ...message, conversationId: incomingConversationId ?? conversationId }];
      });
      if (message.senderId !== user?.id) {
        api(`/messages/${conversationId}/read`, { method: 'PATCH' })
          .then(() => refreshUnreadCount())
          .catch(() => {});
      }
    };

    const onTyping = (data: { userId: string; isTyping: boolean }) => {
      if (data.userId === user?.id) return;
      setTypingUser(data.isTyping ? data.userId : null);
    };

    const onReadReceipt = () => {
      setMessages((prev) =>
        prev.map((m) =>
          m.senderId === user?.id ? { ...m, isRead: true, readAt: new Date().toISOString() } : m
        )
      );
    };

    socket.on(SOCKET_EVENTS.RECEIVE_MESSAGE, onMessage);
    socket.on(SOCKET_EVENTS.TYPING, onTyping);
    socket.on(SOCKET_EVENTS.READ_RECEIPT, onReadReceipt);

    return () => {
      socket.off(SOCKET_EVENTS.RECEIVE_MESSAGE, onMessage);
      socket.off(SOCKET_EVENTS.TYPING, onTyping);
      socket.off(SOCKET_EVENTS.READ_RECEIPT, onReadReceipt);
    };
  }, [socket, conversationId, relatedConversationIds, user?.id, refreshUnreadCount]);

  const emitTyping = (isTyping: boolean) => {
    socket?.emit(SOCKET_EVENTS.TYPING, { conversationId, isTyping });
  };

  const sendMessageWithContent = useCallback(
    async (content: string) => {
      const trimmed = content.trim();
      if (!trimmed || messagingLocked) return false;

      setSending(true);
      emitTyping(false);

      try {
        if (socket && isConnected) {
          socket.emit(SOCKET_EVENTS.SEND_MESSAGE, { conversationId, content: trimmed });
        } else {
          const res = await api<{ data: ChatMessage }>('/messages', {
            method: 'POST',
            body: JSON.stringify({ conversationId, content: trimmed }),
          });
          setMessages((prev) => [...prev, res.data]);
        }
        return true;
      } catch (err) {
        console.error(err);
        return false;
      } finally {
        setSending(false);
      }
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps -- emitTyping uses socket/conversationId
    [conversationId, isConnected, messagingLocked, socket]
  );

  useEffect(() => {
    if (loading || messagingLocked || pendingMessageSentRef.current) return;

    const pending = consumePendingJobMessage();
    if (!pending) return;

    pendingMessageSentRef.current = true;
    void sendMessageWithContent(pending.text);
  }, [loading, messagingLocked, sendMessageWithContent]);

  const handleInputChange = (value: string) => {
    setInput(value);
    emitTyping(true);
    if (typingTimeoutRef.current) clearTimeout(typingTimeoutRef.current);
    typingTimeoutRef.current = setTimeout(() => emitTyping(false), 1500);

    const el = textareaRef.current;
    if (el) {
      el.style.height = 'auto';
      el.style.height = `${Math.min(el.scrollHeight, 128)}px`;
    }
  };

  const sendMessage = async () => {
    const content = input.trim();
    if (!content || sending) return;

    setInput('');
    if (textareaRef.current) textareaRef.current.style.height = 'auto';
    const sent = await sendMessageWithContent(content);
    if (!sent) setInput(content);
  };

  const handleKeyDown = (e: React.KeyboardEvent) => {
    if (e.key === 'Enter' && !e.shiftKey) {
      e.preventDefault();
      sendMessage();
    }
  };

  if (loading) {
    return (
      <div className="flex h-full min-h-0 flex-1 items-center justify-center bg-[var(--home-sand)]/35 text-muted">
        <div className="loading-spinner" />
      </div>
    );
  }

  const hasContextMessage = messages.some((message) => isJobContextMetadata(message.metadata));
  const showPinnedJobContext = jobContext && !hasContextMessage;
  const peerActive = isRecentlyActive(peer?.lastActiveAt);

  const headerInner = (
    <>
      <div className="relative shrink-0">
        <UserAvatar
          firstName={peer?.firstName ?? title ?? 'Chat'}
          lastName={peer?.lastName ?? ''}
          avatarUrl={peer?.avatarUrl}
          size="sm"
          rounded="none"
          ringClassName="ring-1 ring-[#e2ddd2] shadow-none"
        />
        {peerActive ? (
          <span className="absolute bottom-0 right-0 h-2.5 w-2.5 bg-emerald-500 ring-2 ring-white" />
        ) : null}
      </div>
      <div className="min-w-0 flex-1">
        <h2 className="truncate font-bold text-[var(--home-ink)]">{title || 'Chat'}</h2>
        <p className="truncate text-xs text-muted">
          {subtitle ? (
            <span className="text-emerald-700">{subtitle}</span>
          ) : peerActive ? (
            <span className="text-emerald-700">Active now</span>
          ) : (
            'Conversation'
          )}
        </p>
      </div>
    </>
  );

  return (
    <div className="flex h-full min-h-0 flex-1 flex-col overflow-hidden">
      <header className="z-10 flex shrink-0 items-center gap-3 border-b border-[#e2ddd2] bg-[#fffdf9] px-3 py-3 sm:px-4">
        <Link href={backHref} className="lg:hidden">
          <Button variant="ghost" size="icon" className="h-10 w-10 shrink-0 rounded-none">
            <ArrowLeft className="h-5 w-5" />
          </Button>
        </Link>

        {peerProfileHref ? (
          <Link href={peerProfileHref} className="flex min-w-0 flex-1 items-center gap-3 hover:opacity-90">
            {headerInner}
          </Link>
        ) : (
          <div className="flex min-w-0 flex-1 items-center gap-3">{headerInner}</div>
        )}

        <span
          className={cn(
            'h-2 w-2 shrink-0',
            isConnected ? 'bg-emerald-500' : 'bg-slate-300'
          )}
          title={isConnected ? 'Connected' : 'Reconnecting…'}
        />
      </header>

      <div
        ref={messagesContainerRef}
        className="min-h-0 flex-1 space-y-1 overflow-y-auto overscroll-contain bg-[linear-gradient(180deg,rgba(243,239,230,0.55)_0%,rgba(255,253,249,0.9)_40%,#fffdf9_100%)] px-3 py-4 sm:px-5"
      >
        {messages.length === 0 && !showPinnedJobContext ? (
          <div className="mx-auto max-w-sm py-12 text-center">
            <p className="text-sm font-semibold text-[var(--home-ink)]">Start the conversation</p>
            <p className="mt-1 text-sm text-muted">
              Introduce yourself and share what you need help with.
            </p>
          </div>
        ) : null}

        {showPinnedJobContext ? (
          <JobContextCard context={jobContext} role={role} className="mb-3" />
        ) : null}

        {messages.map((message, index) => {
          if (isJobContextMetadata(message.metadata)) {
            return (
              <div key={message.id} className="flex justify-center py-2">
                <JobContextCard context={message.metadata} role={role} />
              </div>
            );
          }

          const isOwn = message.senderId === user?.id;
          const prev = messages[index - 1];
          const showDay =
            !prev ||
            isJobContextMetadata(prev.metadata) ||
            !isSameMessageDay(prev.createdAt, message.createdAt);
          const showAvatar =
            !isOwn &&
            (!prev ||
              isJobContextMetadata(prev.metadata) ||
              prev.senderId !== message.senderId ||
              showDay);

          return (
            <div key={message.id}>
              {showDay ? (
                <div className="my-4 flex items-center gap-3">
                  <div className="h-px flex-1 bg-[#e2ddd2]" />
                  <span className="text-[10px] font-semibold uppercase tracking-wide text-muted">
                    {formatMessageDayLabel(message.createdAt)}
                  </span>
                  <div className="h-px flex-1 bg-[#e2ddd2]" />
                </div>
              ) : null}

              <div
                className={cn(
                  'flex items-end gap-2',
                  isOwn ? 'justify-end' : 'justify-start',
                  showAvatar || isOwn ? 'mt-2' : 'mt-0.5'
                )}
              >
                {!isOwn ? (
                  <div className={cn('w-7 shrink-0', !showAvatar && 'invisible')}>
                    {showAvatar ? (
                      <UserAvatar
                        firstName={message.sender?.firstName ?? peer?.firstName ?? 'U'}
                        lastName={message.sender?.lastName ?? peer?.lastName ?? ''}
                        avatarUrl={message.sender?.avatarUrl ?? peer?.avatarUrl}
                        size="xs"
                        rounded="none"
                        ringClassName="ring-0 shadow-none"
                        className="!h-7 !w-7 text-[10px]"
                      />
                    ) : null}
                  </div>
                ) : null}

                <div
                  className={cn(
                    'max-w-[min(78%,28rem)] px-3.5 py-2.5 shadow-sm',
                    isOwn
                      ? 'bg-[var(--home-ink)] text-white'
                      : 'border border-[#e2ddd2] bg-white text-slate-900'
                  )}
                >
                  <p className="whitespace-pre-wrap break-words text-sm leading-relaxed">
                    {message.content}
                  </p>
                  <div
                    className={cn(
                      'mt-1 flex items-center gap-1.5 text-[10px]',
                      isOwn ? 'justify-end text-white/65' : 'text-slate-400'
                    )}
                  >
                    <span>{formatMessageTime(message.createdAt)}</span>
                    {isOwn && message.isRead ? <span>· Read</span> : null}
                  </div>
                </div>
              </div>
            </div>
          );
        })}

        {typingUser ? (
          <div className="mt-2 flex items-end gap-2">
            <div className="w-7 shrink-0" />
            <div className="border border-[#e2ddd2] bg-white px-3.5 py-2.5">
              <div className="flex gap-1">
                <span className="h-1.5 w-1.5 animate-pulse bg-slate-400" />
                <span className="h-1.5 w-1.5 animate-pulse bg-slate-400 [animation-delay:120ms]" />
                <span className="h-1.5 w-1.5 animate-pulse bg-slate-400 [animation-delay:240ms]" />
              </div>
            </div>
          </div>
        ) : null}
        <div ref={messagesEndRef} />
      </div>

      <footer className="safe-area-bottom shrink-0 border-t border-[#e2ddd2] bg-[#fffdf9] px-3 py-3 sm:px-4">
        {messagingLocked ? (
          <div className="flex flex-col gap-3 border border-amber-200 bg-amber-50 p-3 sm:flex-row sm:items-center sm:justify-between">
            <div className="flex items-start gap-2">
              <ShieldAlert className="mt-0.5 h-4 w-4 shrink-0 text-amber-600" />
              <p className="text-sm text-slate-700">
                Verify your identity to send messages to workers.
              </p>
            </div>
            <Link href="/customer/verification">
              <Button size="sm" variant="accent" className="rounded-none">
                Go to verification
              </Button>
            </Link>
          </div>
        ) : (
          <div className="flex items-end gap-2">
            <textarea
              ref={textareaRef}
              value={input}
              onChange={(e) => handleInputChange(e.target.value)}
              onKeyDown={handleKeyDown}
              placeholder="Write a message…"
              rows={1}
              className="max-h-32 min-h-[48px] flex-1 resize-none border border-[#e2ddd2] bg-white px-3.5 py-3 text-sm text-slate-900 placeholder:text-slate-400 focus:border-[var(--home-amber)] focus:outline-none focus:ring-2 focus:ring-[var(--home-amber)]/20"
            />
            <Button
              size="icon"
              className="h-12 w-12 shrink-0 rounded-none bg-[var(--home-ink)] hover:bg-[var(--home-ink)]/90"
              onClick={sendMessage}
              disabled={!input.trim() || sending}
              aria-label="Send message"
            >
              <Send className="h-5 w-5" />
            </Button>
          </div>
        )}
      </footer>
    </div>
  );
}
