import type { RoomResponse, RoomMemberResponse, RoomMessageResponse, RoomThreadResponse } from '@/client';
import { useRoom, type MessageWithMeta } from '@/contexts';
import { useRoomDraft } from '@/hooks/useRoomDraft';
import { Button } from '@/components/ui/button';
import { Textarea } from '@/components/ui/textarea';
import { cn } from '@/lib/utils';
import { ChevronLeft, Hash, Send, Settings, Timer, Trash2, Users, X, Search, Bell } from 'lucide-react';
import {
  memo,
  useCallback,
  useEffect,
  useImperativeHandle,
  useRef,
  useState,
  type ReactNode,
} from 'react';
import { toast } from 'sonner';
import { RoomAiTasksPanel } from './RoomAiTasksPanel';
import { MentionPopover } from './MentionPopover';
import { RoomMessageEditDialog } from './RoomMessageEditDialog';
import { RoomMessageEditHistoryDialog } from './RoomMessageEditHistoryDialog';
import { RoomMessageList } from './RoomMessageList';
import { RoomParticipantsPanel } from './RoomParticipantsPanel';
import { RoomSettingsPanel } from './RoomSettingsPanel';
import { RoomPerformanceMonitor } from './RoomPerformanceMonitor';
import { RoomMessageSearch } from './RoomMessageSearch';
import { RoomMentionPanel } from './RoomMentionPanel';
import { RoomThreadPanel } from './RoomThreadPanel';

const MENTION_PATTERN = /@([^:@\s]*)(:([^\s]*))?$/;
const MENTION_POPOVER_KEYS = ['Enter', 'Tab', 'ArrowUp', 'ArrowDown'];

export interface ChatInputAreaHandle {
  insertMention: (name: string, type: 'user' | 'ai') => void;
}

interface ChatInputAreaProps {
  roomName: string;
  onSend: (content: string) => void;
  isSending: boolean;
  members: RoomMemberResponse[];
  replyingTo?: { id: string; display_name?: string; content: string } | null;
  onCancelReply?: () => void;
  draft: string;
  onDraftChange: (content: string) => void;
  onClearDraft: () => void;
  ref?: React.Ref<ChatInputAreaHandle>;
}

const ChatInputArea = memo(function ChatInputArea({
  roomName,
  onSend,
  isSending,
  members,
  replyingTo,
  onCancelReply,
  draft,
  onDraftChange,
  onClearDraft,
  ref,
}: ChatInputAreaProps) {
  const textareaRef = useRef<HTMLTextAreaElement>(null);
  const [cursorPosition, setCursorPosition] = useState(0);
  const [showMentionPopover, setShowMentionPopover] = useState(false);

  const handleMentionSelect = useCallback((newValue: string, newCursorPos: number) => {
    onDraftChange(newValue);
    setShowMentionPopover(false);
    setTimeout(() => {
      if (textareaRef.current) {
        textareaRef.current.value = newValue;
        textareaRef.current.setSelectionRange(newCursorPos, newCursorPos);
        textareaRef.current.focus();
      }
    }, 0);
  }, [onDraftChange]);

  useImperativeHandle(ref, () => ({
    insertMention: (name: string) => {
      if (!textareaRef.current) return;
      const value = textareaRef.current.value;
      const cursorPos = textareaRef.current.selectionStart;
      const mentionText = `<user>${name}</user> `;
      const before = value.substring(0, cursorPos);
      const after = value.substring(cursorPos);
      const newValue = before + mentionText + after;
      onDraftChange(newValue);
      setShowMentionPopover(false);
      setTimeout(() => {
        if (textareaRef.current) {
          textareaRef.current.focus();
        }
      }, 0);
    },
  }));

  const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
    const value = e.target.value;
    const cursorPos = e.target.selectionStart;
    onDraftChange(value);
    setCursorPosition(cursorPos);

    // Detect @ mention
    const textBefore = value.substring(0, cursorPos);
    const match = textBefore.match(MENTION_PATTERN);
    if (match) {
      setShowMentionPopover(true);
    } else {
      setShowMentionPopover(false);
    }
  };

  const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
    if (showMentionPopover && MENTION_POPOVER_KEYS.includes(e.key)) {
      e.preventDefault();
      return;
    }

    if (e.key === 'Enter' && !e.shiftKey) {
      e.preventDefault();
      const content = e.currentTarget.value.trim();
      if (content && !isSending) {
        onSend(content);
        onClearDraft();
      }
    }
  };

  return (
    <div className="border-t border-border/70 bg-background p-3">
      {replyingTo && (
        <div className="mb-2 flex items-center gap-2 rounded-md bg-muted/50 px-3 py-2 text-xs">
          <span className="font-medium text-foreground">Replying to {replyingTo.display_name}</span>
          <span className="truncate text-muted-foreground">{replyingTo.content}</span>
          <button onClick={onCancelReply} className="ml-auto text-muted-foreground hover:text-foreground">
            <X className="h-3 w-3" />
          </button>
        </div>
      )}

      <div className="relative">
        <Textarea
          ref={textareaRef}
          value={draft}
          onChange={handleChange}
          onKeyDown={handleKeyDown}
          placeholder={`Message #${roomName}...`}
          className="min-h-[80px] resize-none pr-20"
        />

        <div className="absolute bottom-2 right-2 flex items-center gap-1">
          <Button
            size="sm"
            onClick={() => {
              const content = textareaRef.current?.value.trim();
              if (content && !isSending) {
                onSend(content);
                onClearDraft();
              }
            }}
            disabled={isSending}
            className="h-7 px-3"
          >
            <Send className="mr-1 h-3 w-3" />
            Send
          </Button>
        </div>
      </div>

      {showMentionPopover && (
        <MentionPopover
          members={members}
          inputValue={draft}
          cursorPosition={cursorPosition}
          onSelect={handleMentionSelect}
          textareaRef={textareaRef}
          onOpenChange={setShowMentionPopover}
        />
      )}
    </div>
  );
});

/** Animated slide panel - handles enter/exit animations */
function SlidePanel({
  open,
  width = 'w-[360px]',
  children,
}: {
  open: boolean;
  width?: string;
  children: ReactNode;
}) {
  const [visible, setVisible] = useState(open);
  const [animate, setAnimate] = useState(open);

  useEffect(() => {
    if (open) {
      setVisible(true);
      // Force reflow then animate in
      requestAnimationFrame(() => {
        requestAnimationFrame(() => {
          setAnimate(true);
        });
      });
    } else {
      setAnimate(false);
      const timer = setTimeout(() => setVisible(false), 200);
      return () => clearTimeout(timer);
    }
  }, [open]);

  if (!visible) return null;

  return (
    <aside
      className={`${width} border-l border-border/70 bg-card/50 transition-all duration-200 ease-out ${
        animate ? 'translate-x-0 opacity-100' : 'translate-x-full opacity-0'
      }`}
      style={{ flexShrink: 0 }}
    >
      {children}
    </aside>
  );
}

interface RoomChatPanelProps {
  room: RoomResponse;
  isAdmin: boolean;
  onClose: () => void;
  onDelete: () => void;
}

export function RoomChatPanel({ room, isAdmin, onClose, onDelete }: RoomChatPanelProps) {
  const {
    messages,
    members,
    membersLoading,
    sendMessage,
    editMessage,
    revokeMessage,
    updateRoom,
    wsStatus,
    wsError,
    wsClient,
    threads,
    refreshThreads,
  } = useRoom();

  const messagesEndRef = useRef<HTMLDivElement>(null);
  const chatInputRef = useRef<ChatInputAreaHandle>(null);

  const [replyingTo, setReplyingTo] = useState<MessageWithMeta | null>(null);
  const [editingMessage, setEditingMessage] = useState<MessageWithMeta | null>(null);
  const [editDialogOpen, setEditDialogOpen] = useState(false);
  const [editHistoryDialogOpen, setEditHistoryDialogOpen] = useState(false);
  const [selectedMessageForHistory, setSelectedMessageForHistory] = useState<string>('');
  const [showAiTasks, setShowAiTasks] = useState(false);
  const [showParticipants, setShowParticipants] = useState(false);
  const [showSettings, setShowSettings] = useState(false);
  const [showSearch, setShowSearch] = useState(false);
  const [showMentions, setShowMentions] = useState(false);
  const [isUpdatingRoom, setIsUpdatingRoom] = useState(false);
  const [activeThread, setActiveThread] = useState<{ thread: RoomThreadResponse; parentMessage: MessageWithMeta } | null>(null);
  const [renderedMessageCount, setRenderedMessageCount] = useState<number | undefined>(undefined);

  // Draft management
  const { draft, setDraft, clearDraft } = useRoomDraft(room.id);

  const isWsConnected = wsStatus === 'open';

  const connectionLabel = wsStatus === 'connecting'
    ? 'Connecting...'
    : wsStatus === 'closed'
    ? 'Disconnected'
    : wsStatus === 'error'
    ? (wsError ?? 'Connection error')
    : null;

  // Visual connection status dot (Discord-style)
  const statusDotColor = wsStatus === 'open'
    ? 'bg-green-500'
    : wsStatus === 'connecting'
    ? 'bg-yellow-400 animate-pulse'
    : 'bg-red-500';

  const handleSend = useCallback(
    (content: string) => {
      sendMessage(content, 'text', replyingTo?.id ?? undefined);
      setReplyingTo(null);
    },
    [sendMessage, replyingTo],
  );

  const handleEdit = useCallback((message: MessageWithMeta) => {
    setEditingMessage(message);
    setEditDialogOpen(true);
  }, []);

  const handleViewEditHistory = useCallback((message: MessageWithMeta) => {
    setSelectedMessageForHistory(message.id);
    setEditHistoryDialogOpen(true);
  }, []);

  const handleEditConfirm = useCallback(
    (newContent: string) => {
      if (!editingMessage) return;
      editMessage(editingMessage.id, newContent);
      setEditDialogOpen(false);
      setEditingMessage(null);
      toast.success('Message updated');
    },
    [editingMessage, editMessage],
  );

  const handleRevoke = useCallback(
    (message: MessageWithMeta) => {
      revokeMessage(message.id);
      toast.success('Message deleted');
    },
    [revokeMessage],
  );

  const handleMention = useCallback((name: string, type: 'user' | 'ai') => {
    chatInputRef.current?.insertMention(name, type);
  }, []);

  const handleSelectSearchResult = useCallback((message: RoomMessageResponse) => {
    toast.info(`Selected message from ${message.send_at}`);
    setShowSearch(false);
  }, []);

  const handleUpdateRoom = useCallback(
    async (name: string, isPublic: boolean) => {
      setIsUpdatingRoom(true);
      try {
        await updateRoom(room.id, name, isPublic);
      } finally {
        setIsUpdatingRoom(false);
      }
    },
    [room.id, updateRoom],
  );

  // Thread callbacks
  const handleOpenThread = useCallback((message: MessageWithMeta) => {
    if (!message.thread_id) return;
    const thread = threads.find(t => t.id === message.thread_id);
    if (thread) {
      setActiveThread({ thread, parentMessage: message });
    }
  }, [threads]);

  const handleCreateThread = useCallback(async (message: MessageWithMeta) => {
    if (!wsClient || message.thread_id) return;
    try {
      const thread = await wsClient.threadCreate(room.id, message.seq);
      setActiveThread({ thread, parentMessage: message });
      refreshThreads();
    } catch (err) {
      console.error('Failed to create thread:', err);
      toast.error('Failed to create thread');
    }
  }, [wsClient, room.id, refreshThreads]);

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

  useEffect(() => {
    setReplyingTo(null);
    setEditingMessage(null);
    setEditDialogOpen(false);
    setShowAiTasks(false);
    setShowParticipants(false);
    setShowSettings(false);
    setShowSearch(false);
    setShowMentions(false);
    setActiveThread(null);
  }, [room.id]);

  return (
    <section className="flex h-full min-w-0 flex-1 bg-background">
      <div className="flex min-w-0 flex-1 flex-col">
        <header className="flex h-12 items-center justify-between border-b border-border/70 px-4">
          <div className="min-w-0">
            <div className="flex items-center gap-2">
              <Hash className="h-5 w-5 text-muted-foreground" />
              <h1 className="truncate text-base font-semibold text-foreground">{room.room_name}</h1>
              <span
                className={cn('h-2 w-2 rounded-full', statusDotColor)}
                title={connectionLabel ?? 'Connected'}
              />
              {!room.public && (
                <span className="rounded bg-muted px-1.5 py-0.5 text-[11px] text-muted-foreground">
                  Private
                </span>
              )}
            </div>
            <p className="mt-0.5 text-xs text-muted-foreground">
              {members.length} member{members.length !== 1 ? 's' : ''}
              {messages.length > 0 && ` · ${messages.length} message${messages.length !== 1 ? 's' : ''}`}
              {!isWsConnected && connectionLabel && (
                <span className="ml-2">— {connectionLabel}</span>
              )}
            </p>
          </div>

          <div className="flex items-center gap-1">
            <Button
              variant="ghost"
              size="icon"
              className={cn('h-8 w-8', showMentions && 'bg-muted text-foreground')}
              onClick={() => {
                setShowMentions((v) => !v);
                setShowAiTasks(false);
                setShowParticipants(false);
                setShowSettings(false);
                setShowSearch(false);
              }}
              title="@ Mentions"
            >
              <Bell className="h-4 w-4" />
            </Button>

            <Button
              variant="ghost"
              size="icon"
              className={cn('h-8 w-8', showSearch && 'bg-muted text-foreground')}
              onClick={() => {
                setShowSearch((v) => !v);
                setShowAiTasks(false);
                setShowParticipants(false);
                setShowSettings(false);
                setShowMentions(false);
              }}
              title="Search messages"
            >
              <Search className="h-4 w-4" />
            </Button>

            <Button
              variant="ghost"
              size="icon"
              className={cn('h-8 w-8', showAiTasks && 'bg-muted text-foreground')}
              onClick={() => {
                setShowAiTasks((v) => !v);
                setShowParticipants(false);
                setShowSettings(false);
                setShowSearch(false);
                setShowMentions(false);
              }}
              title="AI tasks"
            >
              <Timer className="h-4 w-4" />
            </Button>

            <Button
              variant="ghost"
              size="icon"
              className={cn('h-8 w-8', showParticipants && 'bg-muted text-foreground')}
              onClick={() => {
                setShowParticipants((v) => !v);
                setShowAiTasks(false);
                setShowSettings(false);
                setShowSearch(false);
                setShowMentions(false);
              }}
              title="Members"
            >
              <Users className="h-4 w-4" />
            </Button>

            {isAdmin && (
              <Button
                variant="ghost"
                size="icon"
                className={cn('h-8 w-8', showSettings && 'bg-muted text-foreground')}
                onClick={() => {
                  setShowSettings((v) => !v);
                  setShowAiTasks(false);
                  setShowParticipants(false);
                  setShowSearch(false);
                  setShowMentions(false);
                }}
                title="Room settings"
              >
                <Settings className="h-4 w-4" />
              </Button>
            )}

            {isAdmin && (
              <Button
                variant="ghost"
                size="icon"
                className="h-8 w-8 text-muted-foreground hover:text-destructive"
                onClick={onDelete}
                title="Delete room"
              >
                <Trash2 className="h-4 w-4" />
              </Button>
            )}

            <Button variant="ghost" size="sm" className="h-8 md:hidden" onClick={onClose}>
              <ChevronLeft className="mr-1 h-4 w-4" />
              Back
            </Button>
          </div>
        </header>

        <div className="flex min-h-0 flex-1 flex-col">
          <RoomMessageList
            roomId={room.id}
            messages={messages}
            messagesEndRef={messagesEndRef}
            onInlineEdit={handleEdit}
            onViewHistory={handleViewEditHistory}
            onRevoke={handleRevoke}
            onReply={setReplyingTo}
            onMention={handleMention}
            onOpenThread={handleOpenThread}
            onCreateThread={handleCreateThread}
            onRenderedCountChange={setRenderedMessageCount}
          />
        </div>

        <ChatInputArea
          ref={chatInputRef}
          roomName={room.room_name ?? 'room'}
          onSend={handleSend}
          isSending={false}
          members={members}
          replyingTo={replyingTo ? { id: replyingTo.id, display_name: replyingTo.display_name ?? undefined, content: replyingTo.content } : null}
          onCancelReply={() => setReplyingTo(null)}
          draft={draft}
          onDraftChange={setDraft}
          onClearDraft={clearDraft}
        />
      </div>

      {/* Side panels with slide animations */}
      <SlidePanel open={showParticipants} width="w-[360px]">
        <RoomParticipantsPanel
          members={members}
          membersLoading={membersLoading}
          onMention={handleMention}
        />
      </SlidePanel>

      <SlidePanel open={showMentions} width="w-[380px]">
        <RoomMentionPanel
          onClose={() => setShowMentions(false)}
          onSelectNotification={(mention) => {
            toast.info(`Navigate to message in ${mention.room_name}`);
            setShowMentions(false);
          }}
        />
      </SlidePanel>

      <SlidePanel open={showSearch} width="w-[400px]">
        <RoomMessageSearch
          roomId={room.id}
          onSelectMessage={handleSelectSearchResult}
          onClose={() => setShowSearch(false)}
        />
      </SlidePanel>

      <SlidePanel open={showAiTasks} width="w-72">
        <RoomAiTasksPanel
          roomId={room.id}
          onClose={() => setShowAiTasks(false)}
        />
      </SlidePanel>

      <SlidePanel open={showSettings && isAdmin} width="w-[380px]">
        <RoomSettingsPanel
          room={room}
          onUpdate={handleUpdateRoom}
          onClose={() => setShowSettings(false)}
          isPending={isUpdatingRoom}
        />
      </SlidePanel>

      {activeThread && (
        <RoomThreadPanel
          roomId={room.id}
          thread={activeThread.thread}
          parentMessage={activeThread.parentMessage}
          onClose={() => setActiveThread(null)}
        />
      )}

      <RoomMessageEditDialog
        open={editDialogOpen}
        onOpenChange={setEditDialogOpen}
        originalContent={editingMessage?.content ?? ''}
        onConfirm={handleEditConfirm}
      />

      <RoomMessageEditHistoryDialog
        open={editHistoryDialogOpen}
        onOpenChange={setEditHistoryDialogOpen}
        messageId={selectedMessageForHistory}
        roomId={room.id}
      />

      <RoomPerformanceMonitor messageCount={messages.length} renderedCount={renderedMessageCount} />
    </section>
  );
}
