import {
  mdiArchiveOutline,
  mdiArrowRight,
  mdiChatOutline,
  mdiClose,
  mdiCogOutline,
  mdiDeleteOutline,
  mdiMenu,
  mdiOpenInNew,
  mdiPencilOutline,
  mdiPlus,
} from '@mdi/js';
import axios from 'axios';
import Link from 'next/link';
import { useRouter } from 'next/router';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import BaseIcon from '../BaseIcon';
import { hasPermission } from '../../helpers/userPermissions';
import { useAppSelector } from '../../stores/hooks';
import ChatMarkdown from './ChatMarkdown';

type AgentSummary = {
  id: string;
  name: string;
  description: string;
  model: string;
  is_default?: boolean;
};

type WorkspaceMessage = {
  id: string;
  role: 'user' | 'assistant' | 'system' | 'tool';
  content?: string;
  content_markdown?: string;
  delivery_status?: string;
  createdAt?: string;
  sent_at?: string;
  completed_at?: string;
  sequence?: number;
  optimistic?: boolean;
  pending?: boolean;
};

type ConversationSummary = {
  id: string;
  title: string;
  summary?: string | null;
  status: 'active' | 'archived' | 'deleted';
  is_pinned?: boolean;
  last_message_at?: string | null;
  createdAt?: string;
  updatedAt?: string;
  agent?: AgentSummary | null;
};

type ConversationDetail = ConversationSummary & {
  client_context_json?: string | null;
  messages: WorkspaceMessage[];
};

type Notice = {
  type: 'success' | 'error';
  message: string;
};

const SUGGESTED_PROMPTS = [
  'Draft a launch checklist for an AI feature release.',
  'Explain how to structure a clean API endpoint with validation.',
  'Create a short spec for a user settings page with profile editing.',
  'Help me plan the next milestone for this workspace product.',
];

const sortConversations = (items: ConversationSummary[]) =>
  [...items].sort((left, right) => {
    if (Boolean(left.is_pinned) !== Boolean(right.is_pinned)) {
      return left.is_pinned ? -1 : 1;
    }

    const leftDate = new Date(left.last_message_at || left.updatedAt || left.createdAt || 0).getTime();
    const rightDate = new Date(right.last_message_at || right.updatedAt || right.createdAt || 0).getTime();

    return rightDate - leftDate;
  });

const formatSidebarTime = (value?: string | null) => {
  if (!value) {
    return 'New';
  }

  const date = new Date(value);
  const diff = Date.now() - date.getTime();

  if (diff < 1000 * 60 * 60 * 24) {
    return new Intl.DateTimeFormat('en-US', {
      hour: 'numeric',
      minute: '2-digit',
    }).format(date);
  }

  return new Intl.DateTimeFormat('en-US', {
    month: 'short',
    day: 'numeric',
  }).format(date);
};

const formatMessageTime = (value?: string) => {
  if (!value) {
    return '';
  }

  return new Intl.DateTimeFormat('en-US', {
    month: 'short',
    day: 'numeric',
    hour: 'numeric',
    minute: '2-digit',
  }).format(new Date(value));
};

const getErrorMessage = (error: unknown, fallback: string) => {
  if (axios.isAxiosError(error)) {
    if (typeof error.response?.data === 'string') {
      return error.response.data;
    }

    if (typeof error.response?.data?.message === 'string') {
      return error.response.data.message;
    }
  }

  if (error instanceof Error) {
    return error.message;
  }

  return fallback;
};

const toConversationSummary = (conversation: ConversationDetail): ConversationSummary => ({
  id: conversation.id,
  title: conversation.title,
  summary: conversation.summary,
  status: conversation.status,
  is_pinned: conversation.is_pinned,
  last_message_at: conversation.last_message_at,
  createdAt: conversation.createdAt,
  updatedAt: conversation.updatedAt,
  agent: conversation.agent,
});

function TypingIndicator() {
  return (
    <div className="flex items-center gap-1 text-slate-400">
      <span className="h-1.5 w-1.5 animate-pulse rounded-full bg-slate-300" />
      <span className="h-1.5 w-1.5 animate-pulse rounded-full bg-slate-300 [animation-delay:120ms]" />
      <span className="h-1.5 w-1.5 animate-pulse rounded-full bg-slate-300 [animation-delay:240ms]" />
    </div>
  );
}

type MessageBubbleProps = {
  currentUserName: string;
  message: WorkspaceMessage;
  streamingText: string;
  streamingMessageId: string | null;
};

function MessageBubble({
  currentUserName,
  message,
  streamingText,
  streamingMessageId,
}: MessageBubbleProps) {
  const isUser = message.role === 'user';
  const isStreaming = streamingMessageId === message.id;
  const isFailed = message.delivery_status === 'failed';
  const rawContent = message.content_markdown || message.content || '';
  const displayTime = formatMessageTime(message.completed_at || message.sent_at || message.createdAt);
  let statusLabel = '';

  if (message.pending) {
    statusLabel = 'thinking';
  } else if (isStreaming) {
    statusLabel = 'responding';
  } else if (message.optimistic) {
    statusLabel = 'sending';
  }

  const bubbleClassName = isUser
    ? 'border border-slate-900 bg-slate-900 text-white shadow-sm'
    : isFailed
      ? 'border border-red-200 bg-red-50 text-red-900 shadow-sm'
      : 'border border-slate-200 bg-white text-slate-900 shadow-sm';
  const avatarLabel = isUser ? currentUserName : 'AI';
  const metaClassName = isUser
    ? 'text-[11px] uppercase tracking-[0.18em] text-white/70'
    : isFailed
      ? 'text-[11px] uppercase tracking-[0.18em] text-red-500'
      : 'text-[11px] uppercase tracking-[0.18em] text-slate-400';

  return (
    <div className={`flex gap-2.5 ${isUser ? 'justify-end' : 'justify-start'}`}>
      {!isUser && (
        <div className="flex h-7 w-7 shrink-0 items-center justify-center rounded-md border border-slate-200 bg-slate-100 text-[10px] font-semibold uppercase tracking-[0.14em] text-slate-600">
          {avatarLabel}
        </div>
      )}
      <div className={`max-w-[34rem] rounded-[12px] px-3.5 py-2.5 ${bubbleClassName}`}>
        <div className={`mb-1.5 flex flex-wrap items-center gap-1.5 ${metaClassName}`}>
          <span>{isUser ? currentUserName : 'Assistant'}</span>
          {statusLabel && (
            <span
              className={`rounded-md px-2 py-1 ${
                isUser
                  ? 'bg-white/10 text-white/80'
                  : isFailed
                    ? 'bg-red-100 text-red-600'
                    : 'bg-slate-100 text-slate-500'
              }`}
            >
              {statusLabel}
            </span>
          )}
          {displayTime && (
            <span className={isUser ? 'text-white/50' : isFailed ? 'text-red-400' : 'text-slate-400'}>
              {displayTime}
            </span>
          )}
        </div>

        {message.pending ? (
          <TypingIndicator />
        ) : isStreaming ? (
          <pre className={`whitespace-pre-wrap font-sans text-[13px] leading-5 ${isUser ? 'text-white' : 'text-slate-700'}`}>{streamingText}</pre>
        ) : (
          <ChatMarkdown
            className={
              isUser
                ? 'text-white [&_a]:text-white [&_a]:decoration-white/60 [&_blockquote]:border-white/20 [&_blockquote]:bg-white/10 [&_blockquote]:text-white [&_code]:border-white/10 [&_code]:bg-white/15 [&_code]:text-white [&_h1]:text-white [&_h2]:text-white [&_h3]:text-white [&_p]:text-white [&_strong]:text-white'
                : isFailed
                  ? 'text-red-900 [&_a]:text-red-700 [&_blockquote]:border-red-200 [&_blockquote]:bg-red-100/70 [&_blockquote]:text-red-900 [&_code]:border-red-200 [&_code]:bg-red-100 [&_code]:text-red-900 [&_h1]:text-red-900 [&_h2]:text-red-900 [&_h3]:text-red-900 [&_p]:text-red-900 [&_strong]:text-red-900'
                  : ''
            }
            content={rawContent}
          />
        )}
      </div>
      {isUser && (
        <div className="flex h-7 w-7 shrink-0 items-center justify-center rounded-md border border-slate-900 bg-slate-900 text-[10px] font-semibold text-white">
          {avatarLabel.slice(0, 1)}
        </div>
      )}
    </div>
  );
}

type ConversationRowProps = {
  conversation: ConversationSummary;
  isActive: boolean;
  onSelect: (id: string) => void;
};

function ConversationRow({ conversation, isActive, onSelect }: ConversationRowProps) {
  return (
    <button
      className={`w-full rounded-[8px] border px-2.5 py-2 text-left ${
        isActive
          ? 'border-slate-900 bg-white text-slate-900'
          : 'border-transparent bg-transparent'
      }`}
      onClick={() => onSelect(conversation.id)}
      type="button"
    >
      <div className="mb-2 flex items-start justify-between gap-3">
        <div className="min-w-0">
          <p className={`truncate text-[12px] font-medium ${isActive ? 'text-slate-900' : 'text-slate-900'}`}>{conversation.title}</p>
          <p className={`mt-0.5 text-[9px] uppercase tracking-[0.14em] ${isActive ? 'text-slate-500' : 'text-slate-400'}`}>
            {conversation.agent?.name || 'General assistant'}
          </p>
        </div>
        <span className={`shrink-0 text-[9px] uppercase tracking-[0.12em] ${isActive ? 'text-slate-400' : 'text-slate-400'}`}>
          {formatSidebarTime(conversation.last_message_at || conversation.updatedAt)}
        </span>
      </div>
      <p className={`line-clamp-2 min-h-[1.75rem] text-[11px] leading-4.5 ${isActive ? 'text-slate-600' : 'text-slate-500'}`}>
        {conversation.summary || 'No messages yet. Start with a prompt to generate the first response.'}
      </p>
      {conversation.status === 'archived' && (
        <span className={`mt-1.5 inline-flex rounded-md border px-2 py-0.5 text-[9px] uppercase tracking-[0.12em] ${
          isActive
            ? 'border-slate-200 bg-slate-100 text-slate-500'
            : 'border-slate-200 bg-slate-100 text-slate-500'
        }`}>
          Archived
        </span>
      )}
    </button>
  );
}

export default function WorkspaceShell() {
  const router = useRouter();
  const composerRef = useRef<HTMLTextAreaElement | null>(null);
  const scrollContainerRef = useRef<HTMLDivElement | null>(null);
  const didBootstrapRef = useRef(false);
  const { currentUser } = useAppSelector((state) => state.auth);

  const [agents, setAgents] = useState<AgentSummary[]>([]);
  const [conversations, setConversations] = useState<ConversationSummary[]>([]);
  const [activeConversation, setActiveConversation] = useState<ConversationDetail | null>(null);
  const [composer, setComposer] = useState('');
  const [selectedAgentId, setSelectedAgentId] = useState('');
  const [notice, setNotice] = useState<Notice | null>(null);
  const [loadingBootstrap, setLoadingBootstrap] = useState(true);
  const [loadingConversation, setLoadingConversation] = useState(false);
  const [sending, setSending] = useState(false);
  const [isSidebarOpen, setIsSidebarOpen] = useState(false);
  const [showArchived, setShowArchived] = useState(false);
  const [isEditingTitle, setIsEditingTitle] = useState(false);
  const [draftTitle, setDraftTitle] = useState('');
  const [optimisticMessages, setOptimisticMessages] = useState<WorkspaceMessage[]>([]);
  const [streamingMessageId, setStreamingMessageId] = useState<string | null>(null);
  const [streamingText, setStreamingText] = useState('');
  const [hasBootstrapped, setHasBootstrapped] = useState(false);

  const currentConversationId =
    typeof router.query.conversationId === 'string' ? router.query.conversationId : null;
  const currentUserName = currentUser?.firstName || currentUser?.email || 'You';
  const canAccessAdmin = hasPermission(currentUser, 'READ_USERS');

  const activeConversations = useMemo(
    () => conversations.filter((conversation) => conversation.status !== 'archived'),
    [conversations],
  );
  const archivedConversations = useMemo(
    () => conversations.filter((conversation) => conversation.status === 'archived'),
    [conversations],
  );
  const visibleMessages = useMemo(
    () => [...(activeConversation?.messages || []), ...optimisticMessages],
    [activeConversation?.messages, optimisticMessages],
  );

  const upsertConversation = useCallback((conversation: ConversationSummary) => {
    setConversations((previous) => {
      const next = previous.filter((item) => item.id !== conversation.id);
      return sortConversations([conversation, ...next]);
    });
  }, []);

  const removeConversation = useCallback((conversationId: string) => {
    setConversations((previous) => previous.filter((conversation) => conversation.id !== conversationId));
  }, []);

  const applyConversationPayload = useCallback(
    (conversation: ConversationDetail) => {
      setActiveConversation(conversation);
      setDraftTitle(conversation.title);
      upsertConversation(toConversationSummary(conversation));
    },
    [upsertConversation],
  );

  const loadBootstrap = useCallback(async () => {
    setLoadingBootstrap(true);
    try {
      const { data } = await axios.get('/workspace/bootstrap');
      setAgents(data.agents || []);
      setConversations(sortConversations(data.conversations || []));
      return data;
    } catch (error) {
      setNotice({
        type: 'error',
        message: getErrorMessage(error, 'Failed to load the workspace.'),
      });
      return { agents: [], conversations: [] };
    } finally {
      setLoadingBootstrap(false);
    }
  }, []);

  const loadConversation = useCallback(
    async (conversationId: string) => {
      setLoadingConversation(true);
      try {
        const { data } = await axios.get(`/workspace/conversations/${conversationId}`);
        applyConversationPayload(data.conversation);
      } catch (error) {
        setNotice({
          type: 'error',
          message: getErrorMessage(error, 'Failed to load this conversation.'),
        });
        setActiveConversation(null);
      } finally {
        setLoadingConversation(false);
      }
    },
    [applyConversationPayload],
  );

  useEffect(() => {
    if (!router.isReady || didBootstrapRef.current) {
      return;
    }

    didBootstrapRef.current = true;

    void (async () => {
      await loadBootstrap();
      setHasBootstrapped(true);
    })();
  }, [router.isReady, loadBootstrap, currentConversationId, router]);

  useEffect(() => {
    if (!hasBootstrapped || !currentConversationId) {
      if (hasBootstrapped && !currentConversationId) {
        setActiveConversation(null);
        setDraftTitle('');
        setOptimisticMessages([]);
      }
      return;
    }

    void loadConversation(currentConversationId);
  }, [hasBootstrapped, currentConversationId, loadConversation]);

  useEffect(() => {
    if (!selectedAgentId && agents.length) {
      const defaultAgent = agents.find((agent) => agent.is_default) || agents[0];
      if (defaultAgent) {
        setSelectedAgentId(defaultAgent.id);
      }
    }
  }, [agents, selectedAgentId]);

  useEffect(() => {
    if (!streamingMessageId) {
      return;
    }

    const streamedMessage = activeConversation?.messages.find((message) => message.id === streamingMessageId);
    const fullText = streamedMessage?.content_markdown || streamedMessage?.content || '';

    if (!fullText) {
      setStreamingMessageId(null);
      setStreamingText('');
      return;
    }

    setStreamingText('');
    let cursor = 0;
    const step = Math.max(12, Math.ceil(fullText.length / 32));

    const timer = window.setInterval(() => {
      cursor = Math.min(fullText.length, cursor + step);
      setStreamingText(fullText.slice(0, cursor));

      if (cursor >= fullText.length) {
        window.clearInterval(timer);
        setStreamingMessageId(null);
      }
    }, 18);

    return () => window.clearInterval(timer);
  }, [activeConversation?.messages, streamingMessageId]);

  useEffect(() => {
    if (!scrollContainerRef.current) {
      return;
    }

    scrollContainerRef.current.scrollTo({
      top: scrollContainerRef.current.scrollHeight,
      behavior: 'smooth',
    });
  }, [visibleMessages.length, loadingConversation, streamingText]);

  const handleNewChat = useCallback(async () => {
    setNotice(null);
    setComposer('');
    setActiveConversation(null);
    setDraftTitle('');
    setIsEditingTitle(false);
    setOptimisticMessages([]);
    setIsSidebarOpen(false);
    await router.push('/workspace');
    composerRef.current?.focus();
  }, [router]);

  const handleConversationSelect = useCallback(
    async (conversationId: string) => {
      setIsSidebarOpen(false);
      await router.push(`/workspace/${conversationId}`);
    },
    [router],
  );

  const handleRenameConversation = useCallback(async () => {
    if (!activeConversation) {
      return;
    }

    const nextTitle = draftTitle.trim();
    if (!nextTitle) {
      setNotice({
        type: 'error',
        message: 'Conversation titles cannot be empty.',
      });
      return;
    }

    try {
      const { data } = await axios.patch(`/workspace/conversations/${activeConversation.id}`, {
        title: nextTitle,
      });
      applyConversationPayload(data.conversation);
      setIsEditingTitle(false);
      setNotice({
        type: 'success',
        message: 'Conversation renamed.',
      });
    } catch (error) {
      setNotice({
        type: 'error',
        message: getErrorMessage(error, 'Failed to rename the conversation.'),
      });
    }
  }, [activeConversation, applyConversationPayload, draftTitle]);

  const handleArchiveConversation = useCallback(async () => {
    if (!activeConversation) {
      return;
    }

    const nextStatus = activeConversation.status === 'archived' ? 'active' : 'archived';

    try {
      const { data } = await axios.patch(`/workspace/conversations/${activeConversation.id}`, {
        status: nextStatus,
      });
      applyConversationPayload(data.conversation);
      setNotice({
        type: 'success',
        message: nextStatus === 'archived' ? 'Conversation archived.' : 'Conversation restored.',
      });
    } catch (error) {
      setNotice({
        type: 'error',
        message: getErrorMessage(error, 'Failed to update the conversation status.'),
      });
    }
  }, [activeConversation, applyConversationPayload]);

  const handleDeleteConversation = useCallback(async () => {
    if (!activeConversation) {
      return;
    }

    const confirmed = window.confirm('Delete this conversation? This action can be undone only from the database.');
    if (!confirmed) {
      return;
    }

    const nextConversation = conversations.find((conversation) => conversation.id !== activeConversation.id);

    try {
      await axios.delete(`/workspace/conversations/${activeConversation.id}`);
      removeConversation(activeConversation.id);
      setNotice({
        type: 'success',
        message: 'Conversation deleted.',
      });

      if (nextConversation) {
        await router.replace(`/workspace/${nextConversation.id}`);
      } else {
        await router.replace('/workspace');
      }
    } catch (error) {
      setNotice({
        type: 'error',
        message: getErrorMessage(error, 'Failed to delete the conversation.'),
      });
    }
  }, [activeConversation, conversations, removeConversation, router]);

  const handleAgentChange = useCallback(
    async (nextAgentId: string) => {
      setSelectedAgentId(nextAgentId);

      if (!activeConversation) {
        return;
      }

      try {
        const { data } = await axios.patch(`/workspace/conversations/${activeConversation.id}`, {
          agentId: nextAgentId,
        });
        applyConversationPayload(data.conversation);
      } catch (error) {
        setNotice({
          type: 'error',
          message: getErrorMessage(error, 'Failed to change the active agent.'),
        });
      }
    },
    [activeConversation, applyConversationPayload],
  );

  const handleSendMessage = useCallback(async () => {
    const messageToSend = composer.trim();

    if (!messageToSend || sending) {
      return;
    }

    setNotice(null);
    setSending(true);
    setComposer('');

    let conversation = activeConversation;
    let createdConversationId: string | null = null;

    try {
      if (!conversation) {
        const { data } = await axios.post('/workspace/conversations', {
          agentId: selectedAgentId || undefined,
        });
        conversation = data.conversation;
        createdConversationId = conversation.id;
        applyConversationPayload(conversation);
      }

      const optimisticBase = Date.now();
      setOptimisticMessages([
        {
          id: `optimistic-user-${optimisticBase}`,
          role: 'user',
          content_markdown: messageToSend,
          createdAt: new Date().toISOString(),
          optimistic: true,
        },
        {
          id: `optimistic-assistant-${optimisticBase}`,
          role: 'assistant',
          content_markdown: '',
          createdAt: new Date().toISOString(),
          pending: true,
        },
      ]);

      const { data } = await axios.post(`/workspace/conversations/${conversation.id}/messages`, {
        content: messageToSend,
        agentId: conversation.agent?.id || selectedAgentId || undefined,
      });

      setOptimisticMessages([]);
      applyConversationPayload(data.conversation);

      const newestAssistant = [...data.conversation.messages]
        .reverse()
        .find((message: WorkspaceMessage) => message.role === 'assistant');

      if (newestAssistant?.id && newestAssistant.delivery_status !== 'failed') {
        setStreamingMessageId(newestAssistant.id);
      }

      if (data.ai_error) {
        setNotice({
          type: 'error',
          message: data.ai_error,
        });
      }

      if (router.asPath !== `/workspace/${data.conversation.id}`) {
        await router.replace(`/workspace/${data.conversation.id}`);
      }
    } catch (error) {
      setOptimisticMessages([]);
      setComposer(messageToSend);
      setNotice({
        type: 'error',
        message: getErrorMessage(error, 'Failed to send the message.'),
      });

      if (createdConversationId) {
        upsertConversation(toConversationSummary(conversation as ConversationDetail));
        if (router.asPath !== `/workspace/${createdConversationId}`) {
          await router.replace(`/workspace/${createdConversationId}`);
        }
      }
    } finally {
      setSending(false);
      composerRef.current?.focus();
    }
  }, [
    activeConversation,
    applyConversationPayload,
    composer,
    router,
    selectedAgentId,
    sending,
    upsertConversation,
  ]);

  const agentSelectionValue = activeConversation?.agent?.id || selectedAgentId;
  const emptyStateAgent = agents.find((agent) => agent.id === agentSelectionValue) || agents[0];
  const activeConversationTimestamp = activeConversation?.last_message_at || activeConversation?.updatedAt;
  const activeConversationMessageCount = activeConversation?.messages.length || 0;

  return (
    <section className="h-[calc(100vh-3.5rem)] bg-[#f5f5f7] px-0 sm:px-1.5 sm:pb-1.5 sm:pt-1.5">
      <div className="grid h-full min-h-0 overflow-hidden border border-slate-200 bg-white shadow-[0_16px_48px_-40px_rgba(15,23,42,0.18)] sm:rounded-[10px] lg:grid-cols-[220px_minmax(0,1fr)]">
        <aside
          className={`absolute inset-y-0 left-0 z-20 flex w-full max-w-[220px] flex-col border-r border-slate-200 bg-[#fafafa] transition duration-200 lg:static lg:translate-x-0 ${
            isSidebarOpen ? 'translate-x-0' : '-translate-x-full lg:translate-x-0'
          }`}
        >
          <div className="border-b border-slate-200 px-3.5 py-3.5">
            <div className="flex items-center justify-between">
              <div>
                <p className="text-[10px] font-semibold uppercase tracking-[0.18em] text-slate-400">
                  Conversations
                </p>
                <h2 className="mt-1 text-[15px] font-semibold text-slate-900">AI workspace</h2>
              </div>
              <button
                className="inline-flex h-8 w-8 items-center justify-center rounded-md border border-slate-200 bg-white text-slate-500 lg:hidden"
                onClick={() => setIsSidebarOpen(false)}
                type="button"
              >
                <BaseIcon path={mdiClose} size={18} />
              </button>
            </div>
            <button
              className="mt-3 inline-flex w-full items-center justify-center gap-1.5 rounded-[8px] bg-slate-900 px-3.5 py-2 text-[13px] font-medium text-white"
              onClick={() => void handleNewChat()}
              type="button"
            >
              <BaseIcon path={mdiPlus} size={18} />
              New chat
            </button>
          </div>

          <div className="flex items-center gap-2 px-3.5 py-2 text-[9px] uppercase tracking-[0.14em] text-slate-400">
            <span>{conversations.length} chats</span>
            <span className="h-1 w-1 rounded-full bg-slate-300" />
            <span>{activeConversations.length} active</span>
          </div>

          <div className="flex-1 space-y-3 overflow-y-auto px-2.5 pb-3.5">
            <div className="space-y-2.5">
              <div className="flex items-center justify-between px-1">
                <p className="text-[10px] font-medium uppercase tracking-[0.14em] text-slate-400">
                  Recent
                </p>
              </div>
              {activeConversations.length ? (
                activeConversations.map((conversation) => (
                  <ConversationRow
                    conversation={conversation}
                    isActive={activeConversation?.id === conversation.id}
                    key={conversation.id}
                    onSelect={(id) => void handleConversationSelect(id)}
                  />
                ))
              ) : (
                <div className="rounded-[10px] border border-dashed border-slate-200 bg-white px-2.5 py-3 text-[11px] leading-4.5 text-slate-500">
                  Your recent chats will appear here after the first message.
                </div>
              )}
            </div>

            <div className="space-y-2.5">
              <button
              className="flex w-full items-center justify-between rounded-[8px] border border-slate-200 bg-white px-2.5 py-2 text-left text-[10px] font-medium uppercase tracking-[0.14em] text-slate-500"
                onClick={() => setShowArchived((previous) => !previous)}
                type="button"
              >
                <span>Archived chats</span>
                <span>{showArchived ? 'Hide' : 'Show'}</span>
              </button>
              {showArchived &&
                (archivedConversations.length ? (
                  archivedConversations.map((conversation) => (
                    <ConversationRow
                      conversation={conversation}
                      isActive={activeConversation?.id === conversation.id}
                      key={conversation.id}
                      onSelect={(id) => void handleConversationSelect(id)}
                    />
                  ))
                ) : (
                  <div className="rounded-[10px] border border-dashed border-slate-200 bg-white px-2.5 py-3 text-[11px] leading-4.5 text-slate-500">
                    Archived chats stay here until you restore them.
                  </div>
                ))}
            </div>
          </div>
        </aside>

        {isSidebarOpen && (
          <button
            aria-label="Close conversation sidebar"
            className="absolute inset-0 z-10 bg-slate-900/40 lg:hidden"
            onClick={() => setIsSidebarOpen(false)}
            type="button"
          />
        )}

        <div className="flex min-h-0 min-w-0 flex-col bg-white">
          <div className="border-b border-slate-200 px-3.5 py-2 md:px-4">
            <div className="flex flex-wrap items-center justify-between gap-3">
              <div className="min-w-0">
                <h1 className="truncate text-[15px] font-semibold tracking-[-0.03em] text-slate-900 md:text-[1.02rem]">
                  {activeConversation?.title || 'Start a focused conversation'}
                </h1>
                <p className="mt-0.5 text-[11px] text-slate-500">
                  {activeConversation
                    ? `Updated ${formatSidebarTime(activeConversationTimestamp)}`
                    : 'Pick an agent, send the first message, and the thread appears on the left automatically.'}
                </p>
              </div>
              <div className="flex flex-wrap items-center gap-2">
                <button
                  className="inline-flex items-center gap-1.5 rounded-md border border-slate-200 bg-white px-2.5 py-1 text-[13px] font-medium text-slate-700 lg:hidden"
                  onClick={() => setIsSidebarOpen(true)}
                  type="button"
                >
                  <BaseIcon path={mdiMenu} size={18} />
                  History
                </button>
                <Link
                  className="inline-flex items-center gap-1.5 rounded-md border border-slate-200 bg-white px-2.5 py-1 text-[13px] font-medium text-slate-700"
                  href="/profile"
                >
                  <BaseIcon path={mdiCogOutline} size={18} />
                  Settings
                </Link>
                {canAccessAdmin && (
                  <Link
                    className="inline-flex items-center gap-1.5 rounded-md border border-slate-200 bg-white px-2.5 py-1 text-[13px] font-medium text-slate-700"
                    href="/dashboard"
                  >
                    <BaseIcon path={mdiOpenInNew} size={18} />
                    Backoffice
                  </Link>
                )}
              </div>
            </div>
          </div>

          <div className="flex min-h-0 flex-1 flex-col">
            {notice && (
              <div className="border-b border-slate-200 px-3.5 py-2.5 md:px-4">
                <div
                  className={`rounded-md border px-2.5 py-2 text-[13px] ${
                    notice.type === 'error'
                      ? 'border-red-200 bg-red-50 text-red-700'
                      : 'border-emerald-200 bg-emerald-50 text-emerald-700'
                  }`}
                >
                  {notice.message}
                </div>
              </div>
            )}

            {activeConversation ? (
              <>
                <div className="border-b border-slate-200 px-3.5 py-2 md:px-4">
                  <div className="flex flex-col gap-3 xl:flex-row xl:items-center xl:justify-between">
                    <div className="min-w-0 flex-1">
                      <div className="mb-1.5 flex flex-wrap items-center gap-1.5">
                        <span className="inline-flex rounded-md border border-slate-200 bg-slate-50 px-2.5 py-1 text-[10px] uppercase tracking-[0.18em] text-slate-500">
                          {activeConversation.status === 'archived' ? 'Archived' : 'Active'}
                        </span>
                        <span className="inline-flex rounded-md border border-slate-200 bg-white px-2.5 py-1 text-[10px] uppercase tracking-[0.18em] text-slate-500">
                          {activeConversation.agent?.name || 'General assistant'}
                        </span>
                        <span className="inline-flex rounded-md border border-slate-200 bg-white px-2.5 py-1 text-[10px] uppercase tracking-[0.18em] text-slate-500">
                          {activeConversationMessageCount} messages
                        </span>
                      </div>
                      {isEditingTitle ? (
                        <div className="flex flex-col gap-3 sm:flex-row sm:items-center">
                          <input
                            className="w-full rounded-md border border-slate-200 bg-white px-3.5 py-2 text-[14px] font-semibold text-slate-900 outline-none ring-0 placeholder:text-slate-400 focus:border-slate-900"
                            onChange={(event) => setDraftTitle(event.target.value)}
                            placeholder="Give this conversation a title"
                            value={draftTitle}
                          />
                          <div className="flex items-center gap-2">
                            <button
                              className="rounded-md bg-slate-900 px-4 py-2 text-sm font-medium text-white"
                              onClick={() => void handleRenameConversation()}
                              type="button"
                            >
                              Save
                            </button>
                            <button
                              className="rounded-md border border-slate-200 px-4 py-2 text-sm font-medium text-slate-600"
                              onClick={() => {
                                setDraftTitle(activeConversation.title);
                                setIsEditingTitle(false);
                              }}
                              type="button"
                            >
                              Cancel
                            </button>
                          </div>
                        </div>
                      ) : (
                        <div className="flex flex-wrap items-center gap-3">
                          <h2 className="truncate text-[15px] font-semibold tracking-[-0.03em] text-slate-900">
                            {activeConversation.title}
                          </h2>
                          <button
                            className="inline-flex h-7 w-7 items-center justify-center rounded-md border border-slate-200 bg-white text-slate-500"
                            onClick={() => setIsEditingTitle(true)}
                            type="button"
                          >
                            <BaseIcon path={mdiPencilOutline} size={18} />
                          </button>
                        </div>
                      )}
                      <p className="mt-0.5 max-w-3xl text-[11px] leading-4.5 text-slate-500">
                        {activeConversation.summary || activeConversation.agent?.description || 'Keep the thread moving.'}
                      </p>
                    </div>

                    <div className="grid gap-2 sm:grid-cols-[minmax(0,1fr)_auto] xl:w-[20rem]">
                      <label className="space-y-1 rounded-[10px] border border-slate-200 bg-slate-50 px-2.5 py-2">
                        <span className="block text-[9px] uppercase tracking-[0.14em] text-slate-400">Agent</span>
                        <select
                          className="w-full bg-transparent text-[12px] text-slate-900 outline-none"
                          onChange={(event) => void handleAgentChange(event.target.value)}
                          value={agentSelectionValue}
                        >
                          {agents.map((agent) => (
                            <option className="bg-white text-slate-900" key={agent.id} value={agent.id}>
                              {agent.name}
                            </option>
                          ))}
                        </select>
                      </label>

                      <div className="flex flex-wrap items-center justify-end gap-1.5 rounded-[10px] border border-slate-200 bg-slate-50 px-2 py-1.5">
                        <button
                          className="inline-flex items-center gap-1 rounded-md border border-slate-200 bg-white px-2.5 py-1 text-[12px] font-medium text-slate-700"
                          onClick={() => void handleArchiveConversation()}
                          type="button"
                        >
                          <BaseIcon path={mdiArchiveOutline} size={16} />
                          {activeConversation.status === 'archived' ? 'Restore' : 'Archive'}
                        </button>
                        <button
                          className="inline-flex items-center gap-1 rounded-md border border-red-200 bg-white px-2.5 py-1 text-[12px] font-medium text-red-600"
                          onClick={() => void handleDeleteConversation()}
                          type="button"
                        >
                          <BaseIcon path={mdiDeleteOutline} size={16} />
                          Delete
                        </button>
                      </div>
                    </div>
                  </div>
                </div>

                <div className="flex min-h-0 flex-1 flex-col">
                  <div className="flex-1 overflow-y-auto bg-[#fcfcfd] px-3.5 py-3.5 md:px-4" ref={scrollContainerRef}>
                    {loadingConversation ? (
                      <div className="space-y-4">
                        <div className="h-28 rounded-[12px] border border-slate-200 bg-white" />
                        <div className="ml-auto h-24 max-w-xl rounded-[12px] border border-slate-900 bg-slate-900/10" />
                        <div className="h-40 rounded-[12px] border border-slate-200 bg-white" />
                      </div>
                    ) : visibleMessages.length ? (
                      <div className="space-y-4">
                        {visibleMessages.map((message) => (
                          <MessageBubble
                            currentUserName={currentUserName}
                            key={message.id}
                            message={message}
                            streamingMessageId={streamingMessageId}
                            streamingText={streamingText}
                          />
                        ))}
                      </div>
                    ) : (
                      <div className="mx-auto flex max-w-3xl flex-col items-center rounded-[14px] border border-dashed border-slate-200 bg-white px-6 py-12 text-center">
                        <div className="mb-5 flex h-16 w-16 items-center justify-center rounded-[10px] border border-slate-200 bg-slate-100 text-slate-600">
                          <BaseIcon path={mdiChatOutline} size={28} />
                        </div>
                        <h3 className="text-2xl font-semibold tracking-[-0.03em] text-slate-900">
                          Keep this thread moving.
                        </h3>
                        <p className="mt-3 max-w-2xl text-sm leading-7 text-slate-500 md:text-base">
                          Ask a follow-up, switch the agent, or keep refining the work without
                          opening a new chat.
                        </p>
                      </div>
                    )}
                  </div>

                  <div className="border-t border-slate-200 bg-white px-3.5 py-2 md:px-4">
                    <div className="rounded-[8px] border border-slate-200 bg-white p-2.5">
                      <div className="mb-2 flex flex-col gap-1.5 lg:flex-row lg:items-center lg:justify-between">
                        <div>
                          <p className="text-[9px] uppercase tracking-[0.14em] text-slate-400">Composer</p>
                          <p className="mt-0.5 text-[11px] text-slate-500">
                            {activeConversation?.status === 'archived'
                              ? 'Sending a message will reopen this archived conversation.'
                              : 'Use Enter to send and Shift+Enter for a new line.'}
                          </p>
                        </div>
                        <div className="rounded-md border border-slate-200 bg-slate-50 px-2.5 py-1 text-[11px] text-slate-600">
                          {activeConversation?.agent?.name || emptyStateAgent?.name || 'General Assistant'}
                        </div>
                      </div>

                      <div className="grid gap-2 lg:grid-cols-[minmax(0,1fr)_165px]">
                        <textarea
                          className="min-h-[62px] w-full resize-none rounded-[10px] border border-slate-200 bg-slate-50 px-3 py-2 text-[13px] leading-5 text-slate-900 outline-none placeholder:text-slate-400 focus:border-slate-900"
                          onChange={(event) => setComposer(event.target.value)}
                          onKeyDown={(event) => {
                            if (event.key === 'Enter' && !event.shiftKey) {
                              event.preventDefault();
                              void handleSendMessage();
                            }
                          }}
                          placeholder="Ask for a draft, plan, code snippet, or product spec…"
                          ref={composerRef}
                          value={composer}
                        />
                        <div className="flex flex-col justify-between gap-2">
                          {!activeConversation && (
                            <label className="rounded-[10px] border border-slate-200 bg-slate-50 px-2.5 py-2 text-sm text-slate-600">
                              <span className="mb-1 block text-[9px] uppercase tracking-[0.14em] text-slate-400">
                                Start with agent
                              </span>
                              <select
                              className="w-full bg-transparent text-[12px] text-slate-900 outline-none"
                                onChange={(event) => setSelectedAgentId(event.target.value)}
                                value={selectedAgentId}
                              >
                                {agents.map((agent) => (
                                  <option className="bg-white text-slate-900" key={agent.id} value={agent.id}>
                                    {agent.name}
                                  </option>
                                ))}
                              </select>
                            </label>
                          )}
                          <button
                            className="inline-flex items-center justify-center gap-1.5 rounded-[8px] bg-slate-900 px-3.5 py-2 text-[12px] font-medium text-white disabled:cursor-not-allowed disabled:opacity-60"
                            disabled={!composer.trim() || sending}
                            onClick={() => void handleSendMessage()}
                            type="button"
                          >
                            {sending ? 'Sending…' : 'Send message'}
                            <BaseIcon path={mdiArrowRight} size={18} />
                          </button>
                          <p className="text-[10px] leading-4 text-slate-400">
                            Saved automatically. Enter sends, Shift+Enter adds a new line.
                          </p>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
              </>
            ) : (
              <div className="flex flex-1 items-center justify-center bg-[#fcfcfd] px-5 py-12 md:px-7">
                <div className="mx-auto flex max-w-4xl flex-col items-start rounded-[14px] border border-slate-200 bg-white p-8 md:p-10">
                  <div className="mb-5 flex h-16 w-16 items-center justify-center rounded-[10px] border border-slate-200 bg-slate-100 text-slate-600">
                    <BaseIcon path={mdiChatOutline} size={28} />
                  </div>
                  <p className="text-xs font-medium uppercase tracking-[0.32em] text-slate-400">
                    New chat
                  </p>
                  <h2 className="mt-3 text-3xl font-semibold tracking-[-0.04em] text-slate-900 md:text-[2.5rem]">
                    Start with one clear prompt.
                  </h2>
                  <p className="mt-4 max-w-3xl text-sm leading-7 text-slate-500 md:text-base">
                    Pick an agent, use one of the prompt starters, or write your own message below.
                    The first send creates the thread and drops it into the left sidebar automatically.
                  </p>

                  <div className="mt-8 grid gap-3 md:grid-cols-2">
                    {SUGGESTED_PROMPTS.map((prompt) => (
                      <button
                        className="rounded-[10px] border border-slate-200 bg-slate-50 px-5 py-4 text-left text-sm leading-6 text-slate-700"
                        key={prompt}
                        onClick={() => {
                          setComposer(prompt);
                          composerRef.current?.focus();
                        }}
                        type="button"
                      >
                        {prompt}
                      </button>
                    ))}
                  </div>

                  <div className="mt-8 grid w-full gap-4 rounded-[14px] border border-slate-200 bg-slate-50 p-5 lg:grid-cols-[minmax(0,1fr)_260px]">
                    <div>
                      <p className="text-xs uppercase tracking-[0.24em] text-slate-400">Selected agent</p>
                      <div className="mt-3 rounded-[10px] border border-slate-200 bg-white px-4 py-4">
                        <p className="text-lg font-medium text-slate-900">
                          {emptyStateAgent?.name || 'General Assistant'}
                        </p>
                        <p className="mt-2 text-sm leading-6 text-slate-500">
                          {emptyStateAgent?.description ||
                            'Choose a starting agent, then send the first message to create the chat.'}
                        </p>
                      </div>
                    </div>

                    <div className="flex flex-col gap-3 lg:w-[260px]">
                      <label className="rounded-[10px] border border-slate-200 bg-white px-4 py-3 text-sm text-slate-600">
                        <span className="mb-2 block text-[11px] uppercase tracking-[0.24em] text-slate-400">
                          Start with agent
                        </span>
                        <select
                          className="w-full bg-transparent text-sm text-slate-900 outline-none"
                          onChange={(event) => setSelectedAgentId(event.target.value)}
                          value={selectedAgentId}
                        >
                          {agents.map((agent) => (
                            <option className="bg-white text-slate-900" key={agent.id} value={agent.id}>
                              {agent.name}
                            </option>
                          ))}
                        </select>
                      </label>
                      <button
                        className="inline-flex items-center justify-center gap-2 rounded-[10px] bg-slate-900 px-5 py-4 text-sm font-medium text-white disabled:cursor-not-allowed disabled:opacity-60"
                        disabled={!composer.trim() || sending || loadingBootstrap}
                        onClick={() => void handleSendMessage()}
                        type="button"
                      >
                        {sending ? 'Creating chat…' : 'Start conversation'}
                        <BaseIcon path={mdiArrowRight} size={18} />
                      </button>
                    </div>
                  </div>

                  <div className="mt-5 w-full rounded-[14px] border border-slate-200 bg-slate-50 p-4">
                    <p className="mb-3 text-xs uppercase tracking-[0.24em] text-slate-400">First message</p>
                    <textarea
                      className="min-h-[140px] w-full resize-none rounded-[10px] border border-slate-200 bg-white px-4 py-4 text-[15px] leading-7 text-slate-900 outline-none placeholder:text-slate-400 focus:border-slate-900"
                      onChange={(event) => setComposer(event.target.value)}
                      onKeyDown={(event) => {
                        if (event.key === 'Enter' && !event.shiftKey) {
                          event.preventDefault();
                          void handleSendMessage();
                        }
                      }}
                      placeholder="Type your first message here to create a conversation…"
                      ref={composerRef}
                      value={composer}
                    />
                  </div>
                </div>
              </div>
            )}
          </div>
        </div>
      </div>
    </section>
  );
}
