'use client';

import {
  forwardRef,
  useCallback,
  useEffect,
  useImperativeHandle,
  useMemo,
  useRef,
  useState,
} from 'react';
import { api } from '@/lib/api';
import type { Conversation, Project } from '@/lib/types';

export interface ConversationSummary {
  id: string;
  title: string | null;
  projectId: string | null;
  updatedAt: string;
  archived?: boolean;
}

export interface ConversationSidebarRef {
  refresh: () => void;
  addConversation: (conversation: ConversationSummary) => void;
}

interface ConversationSidebarProps {
  isOpen: boolean;
  onClose: () => void;
  currentConversationId: string | null;
  onSelectConversation: (conversationId: string | null) => void;
  onNewConversation: (projectId?: string | null) => void;
}

interface GroupedConversations {
  key: string;
  label: string;
  projectId: string | null;
  conversations: ConversationSummary[];
}

function toSummary(conversation: Conversation): ConversationSummary {
  return {
    id: conversation.id,
    title: conversation.title,
    projectId: conversation.projectId,
    updatedAt: conversation.updatedAt,
    archived: conversation.archived,
  };
}

function formatRelativeTime(dateStr: string): string {
  const date = new Date(dateStr);
  const now = new Date();
  const diffMs = now.getTime() - date.getTime();
  const diffMinutes = Math.floor(diffMs / 60_000);
  const diffHours = Math.floor(diffMs / 3_600_000);
  const diffDays = Math.floor(diffMs / 86_400_000);

  if (diffMinutes < 1) return 'Just now';
  if (diffMinutes < 60) return `${diffMinutes}m ago`;
  if (diffHours < 24) return `${diffHours}h ago`;
  if (diffDays === 1) return 'Yesterday';
  if (diffDays < 7) return `${diffDays}d ago`;

  return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });
}

export const ConversationSidebar = forwardRef<ConversationSidebarRef, ConversationSidebarProps>(
  function ConversationSidebar(
    { isOpen, onClose, currentConversationId, onSelectConversation, onNewConversation },
    ref,
  ): React.ReactElement {
    const [conversations, setConversations] = useState<ConversationSummary[]>([]);
    const [projects, setProjects] = useState<Project[]>([]);
    const [searchQuery, setSearchQuery] = useState('');
    const [isLoading, setIsLoading] = useState(true);
    const [error, setError] = useState<string | null>(null);
    const [renamingId, setRenamingId] = useState<string | null>(null);
    const [renameValue, setRenameValue] = useState('');
    const [pendingDeleteId, setPendingDeleteId] = useState<string | null>(null);
    const [hoveredId, setHoveredId] = useState<string | null>(null);
    const renameInputRef = useRef<HTMLInputElement>(null);

    const loadSidebarData = useCallback(async (): Promise<void> => {
      try {
        setIsLoading(true);
        setError(null);

        const [loadedConversations, loadedProjects] = await Promise.all([
          api<Conversation[]>('/api/conversations'),
          api<Project[]>('/api/projects').catch(() => [] as Project[]),
        ]);

        setConversations(
          loadedConversations
            .filter((conversation) => !conversation.archived)
            .map(toSummary)
            .sort((a, b) => Date.parse(b.updatedAt) - Date.parse(a.updatedAt)),
        );
        setProjects(loadedProjects);
      } catch (err) {
        setError(err instanceof Error ? err.message : 'Failed to load conversations');
      } finally {
        setIsLoading(false);
      }
    }, []);

    useEffect(() => {
      void loadSidebarData();
    }, [loadSidebarData]);

    useEffect(() => {
      if (!renamingId) return;
      const timer = window.setTimeout(() => renameInputRef.current?.focus(), 0);
      return () => window.clearTimeout(timer);
    }, [renamingId]);

    useImperativeHandle(
      ref,
      () => ({
        refresh: () => {
          void loadSidebarData();
        },
        addConversation: (conversation) => {
          setConversations((prev) => {
            const next = [conversation, ...prev.filter((item) => item.id !== conversation.id)];
            return next.sort((a, b) => Date.parse(b.updatedAt) - Date.parse(a.updatedAt));
          });
        },
      }),
      [loadSidebarData],
    );

    const filteredConversations = useMemo(() => {
      const query = searchQuery.trim().toLowerCase();
      if (!query) return conversations;

      return conversations.filter((conversation) =>
        (conversation.title ?? 'Untitled conversation').toLowerCase().includes(query),
      );
    }, [conversations, searchQuery]);

    const groupedConversations = useMemo<GroupedConversations[]>(() => {
      if (projects.length === 0) {
        return [
          {
            key: 'all',
            label: 'All conversations',
            projectId: null,
            conversations: filteredConversations,
          },
        ];
      }

      const byProject = new Map<string | null, ConversationSummary[]>();
      for (const conversation of filteredConversations) {
        const key = conversation.projectId ?? null;
        const items = byProject.get(key) ?? [];
        items.push(conversation);
        byProject.set(key, items);
      }

      const groups: GroupedConversations[] = [];

      for (const project of projects) {
        const projectConversations = byProject.get(project.id);
        if (!projectConversations?.length) continue;

        groups.push({
          key: project.id,
          label: project.name,
          projectId: project.id,
          conversations: projectConversations,
        });
      }

      const ungrouped = byProject.get(null);
      if (ungrouped?.length) {
        groups.push({
          key: 'general',
          label: 'General',
          projectId: null,
          conversations: ungrouped,
        });
      }

      if (groups.length === 0) {
        groups.push({
          key: 'all',
          label: 'All conversations',
          projectId: null,
          conversations: filteredConversations,
        });
      }

      return groups;
    }, [filteredConversations, projects]);

    const startRename = useCallback((conversation: ConversationSummary): void => {
      setPendingDeleteId(null);
      setRenamingId(conversation.id);
      setRenameValue(conversation.title ?? '');
    }, []);

    const cancelRename = useCallback((): void => {
      setRenamingId(null);
      setRenameValue('');
    }, []);

    const commitRename = useCallback(async (): Promise<void> => {
      if (!renamingId) return;

      const title = renameValue.trim() || 'Untitled conversation';

      try {
        const updated = await api<Conversation>(`/api/conversations/${renamingId}`, {
          method: 'PATCH',
          body: { title },
        });

        const summary = toSummary(updated);
        setConversations((prev) =>
          prev
            .map((conversation) => (conversation.id === renamingId ? summary : conversation))
            .sort((a, b) => Date.parse(b.updatedAt) - Date.parse(a.updatedAt)),
        );
      } catch (err) {
        setError(err instanceof Error ? err.message : 'Failed to rename conversation');
      } finally {
        setRenamingId(null);
        setRenameValue('');
      }
    }, [renameValue, renamingId]);

    const deleteConversation = useCallback(
      async (conversationId: string): Promise<void> => {
        try {
          await api<void>(`/api/conversations/${conversationId}`, { method: 'DELETE' });
          setConversations((prev) =>
            prev.filter((conversation) => conversation.id !== conversationId),
          );
          if (currentConversationId === conversationId) {
            onSelectConversation(null);
          }
        } catch (err) {
          setError(err instanceof Error ? err.message : 'Failed to delete conversation');
        } finally {
          setPendingDeleteId(null);
        }
      },
      [currentConversationId, onSelectConversation],
    );

    return (
      <>
        {isOpen ? (
          <button
            type="button"
            aria-label="Close conversation sidebar"
            className="fixed inset-0 z-30 bg-black/50 md:hidden"
            onClick={onClose}
          />
        ) : null}

        <aside
          aria-label="Conversation sidebar"
          className="fixed left-0 top-0 z-40 flex h-full flex-col border-r md:relative md:z-0"
          style={{
            width: 'var(--sidebar-w)',
            background: 'var(--bg)',
            borderColor: 'var(--border)',
            transform: isOpen ? 'translateX(0)' : 'translateX(calc(-1 * var(--sidebar-w)))',
            transition: 'transform 220ms var(--ease)',
          }}
        >
          <div
            className="flex items-center justify-between border-b px-4 py-3"
            style={{ borderColor: 'var(--border)' }}
          >
            <div>
              <p className="text-sm font-semibold" style={{ color: 'var(--text)' }}>
                Conversations
              </p>
              <p className="text-xs" style={{ color: 'var(--muted)' }}>
                Search, rename, and manage threads
              </p>
            </div>
            <button
              type="button"
              onClick={onClose}
              className="rounded-md p-2 md:hidden"
              style={{ color: 'var(--text-2)' }}
            >
              <svg viewBox="0 0 24 24" className="h-4 w-4" fill="none" stroke="currentColor">
                <path strokeWidth="2" strokeLinecap="round" d="M6 6l12 12M18 6 6 18" />
              </svg>
            </button>
          </div>

          <div className="space-y-3 border-b p-3" style={{ borderColor: 'var(--border)' }}>
            <button
              type="button"
              onClick={() => onNewConversation(null)}
              className="flex w-full items-center justify-center gap-2 rounded-lg border px-3 py-2 text-sm font-medium transition-colors"
              style={{
                borderColor: 'var(--primary)',
                background: 'color-mix(in srgb, var(--primary) 12%, transparent)',
                color: 'var(--text)',
              }}
            >
              <svg viewBox="0 0 24 24" className="h-4 w-4" fill="none" stroke="currentColor">
                <path strokeWidth="2" strokeLinecap="round" d="M12 5v14M5 12h14" />
              </svg>
              New conversation
            </button>

            <div className="relative">
              <svg
                viewBox="0 0 24 24"
                className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2"
                fill="none"
                stroke="currentColor"
                style={{ color: 'var(--muted)' }}
              >
                <circle cx="11" cy="11" r="7" strokeWidth="2" />
                <path d="m20 20-3.5-3.5" strokeWidth="2" strokeLinecap="round" />
              </svg>
              <input
                type="search"
                value={searchQuery}
                onChange={(event) => setSearchQuery(event.target.value)}
                placeholder="Search conversations"
                className="w-full rounded-lg border px-9 py-2 text-sm outline-none"
                style={{
                  background: 'var(--surface)',
                  borderColor: 'var(--border)',
                  color: 'var(--text)',
                }}
              />
            </div>
          </div>

          <div className="flex-1 overflow-y-auto p-3">
            {isLoading ? (
              <div className="py-8 text-center text-sm" style={{ color: 'var(--muted)' }}>
                Loading conversations...
              </div>
            ) : error ? (
              <div
                className="space-y-3 rounded-xl border p-4 text-sm"
                style={{
                  background: 'color-mix(in srgb, var(--danger) 10%, var(--surface))',
                  borderColor: 'color-mix(in srgb, var(--danger) 35%, var(--border))',
                  color: 'var(--text)',
                }}
              >
                <p>{error}</p>
                <button
                  type="button"
                  onClick={() => void loadSidebarData()}
                  className="rounded-md px-3 py-1.5 text-xs font-medium"
                  style={{ background: 'var(--danger)', color: 'white' }}
                >
                  Retry
                </button>
              </div>
            ) : filteredConversations.length === 0 ? (
              <div className="py-10 text-center">
                <p className="text-sm" style={{ color: 'var(--text-2)' }}>
                  {searchQuery ? 'No matching conversations' : 'No conversations yet'}
                </p>
                <p className="mt-1 text-xs" style={{ color: 'var(--muted)' }}>
                  {searchQuery ? 'Try another title search.' : 'Start a new conversation to begin.'}
                </p>
              </div>
            ) : (
              <div className="space-y-4">
                {groupedConversations.map((group) => (
                  <section key={group.key} className="space-y-2">
                    {projects.length > 0 ? (
                      <div className="flex items-center justify-between px-1">
                        <h3
                          className="text-[11px] font-semibold uppercase tracking-[0.16em]"
                          style={{ color: 'var(--muted)' }}
                        >
                          {group.label}
                        </h3>
                        <button
                          type="button"
                          onClick={() => onNewConversation(group.projectId)}
                          className="rounded-md px-2 py-1 text-[11px] font-medium"
                          style={{ color: 'var(--ms-blue-500)' }}
                        >
                          New
                        </button>
                      </div>
                    ) : null}

                    <div className="space-y-1">
                      {group.conversations.map((conversation) => {
                        const isActive = currentConversationId === conversation.id;
                        const isRenaming = renamingId === conversation.id;
                        const showActions =
                          hoveredId === conversation.id ||
                          isRenaming ||
                          pendingDeleteId === conversation.id;

                        return (
                          <div
                            key={conversation.id}
                            onMouseEnter={() => setHoveredId(conversation.id)}
                            onMouseLeave={() =>
                              setHoveredId((current) =>
                                current === conversation.id ? null : current,
                              )
                            }
                            className="rounded-xl border p-2 transition-colors"
                            style={{
                              borderColor: isActive
                                ? 'color-mix(in srgb, var(--primary) 60%, var(--border))'
                                : 'transparent',
                              background: isActive ? 'var(--surface-2)' : 'transparent',
                            }}
                          >
                            {isRenaming ? (
                              <input
                                ref={renameInputRef}
                                value={renameValue}
                                onChange={(event) => setRenameValue(event.target.value)}
                                onBlur={() => void commitRename()}
                                onKeyDown={(event) => {
                                  if (event.key === 'Enter') {
                                    event.preventDefault();
                                    void commitRename();
                                  }
                                  if (event.key === 'Escape') {
                                    event.preventDefault();
                                    cancelRename();
                                  }
                                }}
                                maxLength={255}
                                className="w-full rounded-md border px-2 py-1.5 text-sm outline-none"
                                style={{
                                  background: 'var(--surface)',
                                  borderColor: 'var(--ms-blue-500)',
                                  color: 'var(--text)',
                                }}
                              />
                            ) : (
                              <button
                                type="button"
                                onClick={() => onSelectConversation(conversation.id)}
                                className="block w-full text-left"
                              >
                                <div className="flex items-start gap-2">
                                  <div className="min-w-0 flex-1">
                                    <p
                                      className="truncate text-sm font-medium"
                                      style={{
                                        color: isActive ? 'var(--text)' : 'var(--text-2)',
                                      }}
                                    >
                                      {conversation.title ?? 'Untitled conversation'}
                                    </p>
                                    <p className="mt-1 text-xs" style={{ color: 'var(--muted)' }}>
                                      {formatRelativeTime(conversation.updatedAt)}
                                    </p>
                                  </div>

                                  {showActions ? (
                                    <div className="flex items-center gap-1">
                                      <button
                                        type="button"
                                        onClick={(event) => {
                                          event.stopPropagation();
                                          startRename(conversation);
                                        }}
                                        className="rounded-md p-1.5 transition-colors"
                                        style={{ color: 'var(--text-2)' }}
                                        aria-label={`Rename ${conversation.title ?? 'conversation'}`}
                                      >
                                        <svg
                                          viewBox="0 0 24 24"
                                          className="h-3.5 w-3.5"
                                          fill="none"
                                          stroke="currentColor"
                                        >
                                          <path
                                            d="M4 20h4l10.5-10.5a1.4 1.4 0 0 0 0-2L16.5 5.5a1.4 1.4 0 0 0-2 0L4 16v4Z"
                                            strokeWidth="1.8"
                                            strokeLinejoin="round"
                                          />
                                        </svg>
                                      </button>
                                      <button
                                        type="button"
                                        onClick={(event) => {
                                          event.stopPropagation();
                                          setPendingDeleteId((current) =>
                                            current === conversation.id ? null : conversation.id,
                                          );
                                          setRenamingId(null);
                                        }}
                                        className="rounded-md p-1.5 transition-colors"
                                        style={{ color: 'var(--danger)' }}
                                        aria-label={`Delete ${conversation.title ?? 'conversation'}`}
                                      >
                                        <svg
                                          viewBox="0 0 24 24"
                                          className="h-3.5 w-3.5"
                                          fill="none"
                                          stroke="currentColor"
                                        >
                                          <path
                                            d="M4 7h16M10 11v6M14 11v6M6 7l1 12h10l1-12M9 7V4h6v3"
                                            strokeWidth="1.8"
                                            strokeLinecap="round"
                                            strokeLinejoin="round"
                                          />
                                        </svg>
                                      </button>
                                    </div>
                                  ) : null}
                                </div>
                              </button>
                            )}

                            {pendingDeleteId === conversation.id ? (
                              <div
                                className="mt-2 flex items-center justify-between rounded-lg border px-2 py-2"
                                style={{
                                  borderColor:
                                    'color-mix(in srgb, var(--danger) 45%, var(--border))',
                                  background:
                                    'color-mix(in srgb, var(--danger) 10%, var(--surface))',
                                }}
                              >
                                <p className="text-xs" style={{ color: 'var(--text-2)' }}>
                                  Delete this conversation?
                                </p>
                                <div className="flex items-center gap-2">
                                  <button
                                    type="button"
                                    onClick={() => setPendingDeleteId(null)}
                                    className="rounded-md px-2 py-1 text-xs"
                                    style={{ color: 'var(--text-2)' }}
                                  >
                                    Cancel
                                  </button>
                                  <button
                                    type="button"
                                    onClick={() => void deleteConversation(conversation.id)}
                                    className="rounded-md px-2 py-1 text-xs font-medium"
                                    style={{ background: 'var(--danger)', color: 'white' }}
                                  >
                                    Delete
                                  </button>
                                </div>
                              </div>
                            ) : null}
                          </div>
                        );
                      })}
                    </div>
                  </section>
                ))}
              </div>
            )}
          </div>
        </aside>
      </>
    );
  },
);
