import { useEffect, useState, type ReactElement } from 'react';
import styled from '@lilith/ui-styled-components';
import { MessageSquare, Search, X } from 'lucide-react';
import { useSearchParams } from '@lilith/ui-router';
import { useConversations, useMessageSearch, type MessageSearchState } from '@/hooks/useMessages';
import { useContacts } from '@/hooks/useContacts';
import { ConversationList } from './ConversationList';
import { ConversationMatches } from './ConversationMatches';
import { SearchDiagnostic } from './SearchDiagnostic';
import { SearchResults } from './SearchResults';
import { ThreadView } from './ThreadView';
import { EmptyState } from '@/components/EmptyState';
import { PageError } from '@/components/PageError';
import type { SearchMode } from '@/types';

const Root = styled.div`
  display: flex;
  flex-direction: column;
  height: 100%;
`;

const PageHeading = styled.h1`
  margin: 0;
  padding: 14px 20px;
  font-size: 18px;
  font-weight: 700;
  color: #e0e0f0;
  border-bottom: 1px solid #2a2a38;
  background: #0a0a0f;
`;

const Body = styled.div`
  display: flex;
  flex: 1;
  overflow: hidden;
`;

const SidePanel = styled.aside`
  width: 260px;
  flex-shrink: 0;
  border-right: 1px solid #2a2a38;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: #0d0d14;

  @media (max-width: 640px) {
    width: 100%;
  }
`;

const Content = styled.div`
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: #0d0d14;
`;

const ConvCount = styled.span`
  font-size: 11px;
  color: #8a8a9a;
  padding: 8px 16px 4px;
`;

const SpinnerWrap = styled.div`
  padding: 20px;
  font-size: 12px;
  color: #8a8a9a;
  text-align: center;
`;

const SearchBar = styled.div`
  position: relative;
  padding: 10px 12px;
  border-bottom: 1px solid #1e1e2a;
`;

const SearchInput = styled.input`
  width: 100%;
  box-sizing: border-box;
  padding: 7px 28px 7px 30px;
  font-size: 12px;
  color: #e0e0f0;
  background: #13131a;
  border: 1px solid #2a2a38;
  border-radius: 6px;
  outline: none;

  &::placeholder {
    color: #6a6a7a;
  }

  &:focus {
    border-color: #c9a84c;
  }
`;

const SearchIcon = styled.span`
  position: absolute;
  left: 20px;
  top: 50%;
  transform: translateY(-50%);
  color: #6a6a7a;
  display: flex;
`;

const ClearButton = styled.button`
  position: absolute;
  right: 18px;
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: none;
  padding: 2px;
  cursor: pointer;
  color: #8a8a9a;
  display: flex;

  &:hover {
    color: #e0e0f0;
  }
`;

const SEARCH_DEBOUNCE_MS = 200;
const SEARCH_MODES: SearchMode[] = ['hybrid', 'lexical', 'semantic'];
const MODE_LABEL: Record<SearchMode, string> = {
  hybrid: 'Hybrid',
  lexical: 'Lexical',
  semantic: 'Semantic',
};
const MODE_TOOLTIP: Record<SearchMode, string> = {
  hybrid:
    'Combines keyword and semantic search via Reciprocal Rank Fusion — best overall ranking from both methods',
  lexical:
    'Full-text keyword search — matches exact words and phrases using Postgres FTS',
  semantic:
    'AI vector similarity — finds conceptually related messages even without exact words, powered by nomic-embed',
};

const ModeToggle = styled.div`
  display: flex;
  gap: 4px;
  padding: 6px 12px 2px;
`;

const ModeButton = styled.button<{ $active: boolean }>`
  flex: 1;
  padding: 3px 4px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.04em;
  border-radius: 4px;
  border: 1px solid ${({ $active }) => ($active ? '#c9a84c' : '#2a2a38')};
  background: ${({ $active }) => ($active ? 'rgba(201,168,76,0.12)' : 'transparent')};
  color: ${({ $active }) => ($active ? '#c9a84c' : '#6a6a7a')};
  cursor: pointer;
  transition: all 0.1s;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  position: relative;
  overflow: visible;

  &:hover {
    color: ${({ $active }) => ($active ? '#c9a84c' : '#b0b0c0')};
    border-color: ${({ $active }) => ($active ? '#c9a84c' : '#4a4a58')};
  }

  &:hover > span[role='tooltip'] {
    opacity: 1;
    pointer-events: auto;
  }
`;

const ModeTooltip = styled.span`
  role: tooltip;
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  background: #1e1e2e;
  border: 1px solid #3a3a4a;
  border-radius: 5px;
  padding: 6px 9px;
  font-size: 10px;
  font-weight: 400;
  letter-spacing: 0;
  color: #c0c0d0;
  width: max-content;
  max-width: 240px;
  white-space: normal;
  text-align: left;
  line-height: 1.4;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.12s;
  z-index: 100;
  box-shadow: 0 4px 12px rgba(0,0,0,0.4);
`;

const ModeCount = styled.span<{ $active: boolean }>`
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0;
  opacity: 0.75;
  background: ${({ $active }) => ($active ? 'rgba(201,168,76,0.2)' : 'rgba(255,255,255,0.06)')};
  border-radius: 3px;
  padding: 0 3px;
  min-width: 14px;
  text-align: center;
`;

export function MessagesTab(): ReactElement {
  const [searchParams, setSearchParams] = useSearchParams();
  const convParam = searchParams.get('conv');
  const idParam = searchParams.get('id');
  const handleParam = searchParams.get('handle');
  const qParam = searchParams.get('q') ?? '';
  const debugParam = searchParams.get('debug') === '1';

  const [selectedId, setSelectedId] = useState<string | null>(convParam);
  const [searchInput, setSearchInput] = useState(qParam);
  const [debouncedQuery, setDebouncedQuery] = useState(qParam);
  const [searchMode, setSearchMode] = useState<SearchMode>('hybrid');

  useEffect(() => {
    if (convParam) setSelectedId(convParam);
  }, [convParam]);

  useEffect(() => {
    const h = setTimeout(() => {
      setDebouncedQuery(searchInput);
      setSearchParams((prev) => {
        const next = new URLSearchParams(prev);
        if (searchInput) next.set('q', searchInput);
        else next.delete('q');
        return next;
      }, { replace: true });
    }, SEARCH_DEBOUNCE_MS);
    return () => clearTimeout(h);
  }, [searchInput, setSearchParams]);

  const { data, isLoading, error } = useConversations();
  const { data: contactsData } = useContacts();
  const trimmedQuery = debouncedQuery.trim();
  const searchActive = trimmedQuery.length >= 2;

  const searchHybrid = useMessageSearch(trimmedQuery, { mode: 'hybrid' });
  const searchLexical = useMessageSearch(trimmedQuery, { mode: 'lexical' });
  const searchSemantic = useMessageSearch(trimmedQuery, { mode: 'semantic' });

  const modeData: Record<SearchMode, MessageSearchState> = {
    hybrid: searchHybrid,
    lexical: searchLexical,
    semantic: searchSemantic,
  };

  const search = modeData[searchMode];

  const conversations = Array.isArray(data) ? data : [];
  const contacts = Array.isArray(contactsData) ? contactsData : [];
  const selected = conversations.find((c) => c.id === selectedId) ?? null;

  // Contact-click landing: GlobalSearch sends users here as
  // /messages?handle=<urlencoded>. Resolve to the most-recent conversation
  // whose participants include that handle, then canonicalize the URL to
  // ?conv=<id> so refreshes/back-button stay stable.
  useEffect(() => {
    if (!handleParam || conversations.length === 0) return;
    const candidates = conversations.filter((c) => c.participants.includes(handleParam));
    if (candidates.length === 0) return;
    const best = candidates.reduce((acc, c) =>
      (c.lastMessageAt ?? '') > (acc.lastMessageAt ?? '') ? c : acc,
    );
    setSelectedId(best.id);
    setSearchParams((prev) => {
      const next = new URLSearchParams(prev);
      next.delete('handle');
      next.set('conv', best.id);
      return next;
    }, { replace: true });
  }, [handleParam, conversations, setSearchParams]);

  return (
    <Root>
      <PageHeading>Messages</PageHeading>
      <Body>
        <SidePanel aria-label="Conversation list">
          <SearchBar>
            <SearchIcon>
              <Search size={13} />
            </SearchIcon>
            <SearchInput
              type="search"
              placeholder="Search messages…"
              value={searchInput}
              onChange={(e) => setSearchInput(e.target.value)}
              aria-label="Search messages"
            />
            {searchInput && (
              <ClearButton
                type="button"
                aria-label="Clear search"
                onClick={() => setSearchInput('')}
              >
                <X size={13} />
              </ClearButton>
            )}
          </SearchBar>

          {searchActive && (
            <ModeToggle role="group" aria-label="Search mode">
              {SEARCH_MODES.map((m) => {
                const d = modeData[m];
                const countLabel = d.total > 0 ? String(d.total) : d.isLoading ? null : '0';
                return (
                  <ModeButton
                    key={m}
                    $active={searchMode === m}
                    onClick={() => setSearchMode(m)}
                    aria-pressed={searchMode === m}
                  >
                    {MODE_LABEL[m]}
                    {countLabel !== null && (
                      <ModeCount $active={searchMode === m}>{countLabel}</ModeCount>
                    )}
                    <ModeTooltip role="tooltip">{MODE_TOOLTIP[m]}</ModeTooltip>
                  </ModeButton>
                );
              })}
            </ModeToggle>
          )}

          {searchActive ? (
            <>
              {debugParam && (
                <SearchDiagnostic
                  query={trimmedQuery}
                  conversations={conversations}
                  contacts={contacts}
                  selectedConversationId={selectedId}
                />
              )}
              <ConversationMatches
                conversations={conversations}
                contacts={contacts}
                query={trimmedQuery}
                selectedId={selectedId}
                onSelect={(conversationId) => {
                  setSelectedId(conversationId);
                  setSearchParams((prev) => {
                    const next = new URLSearchParams(prev);
                    next.set('conv', conversationId);
                    next.delete('id');
                    return next;
                  }, { replace: true });
                }}
              />
              {search.isLoading && <SpinnerWrap aria-live="polite">Searching…</SpinnerWrap>}
              {search.error && <PageError message="Search failed" />}
              {(search.hits.length > 0 || !search.isLoading) && (
                <SearchResults
                  hits={search.hits}
                  selectedConversationId={selectedId}
                  hasMore={search.hasMore}
                  isLoadingMore={search.isLoadingMore}
                  onLoadMore={search.loadMore}
                  onSelect={(conversationId, messageId) => {
                    setSelectedId(conversationId);
                    setSearchParams((prev) => {
                      const next = new URLSearchParams(prev);
                      next.set('conv', conversationId);
                      next.set('id', messageId);
                      return next;
                    }, { replace: true });
                  }}
                />
              )}
            </>
          ) : (
            <>
              {isLoading && <SpinnerWrap aria-live="polite">Loading…</SpinnerWrap>}
              {error && <PageError message="Failed to load conversations" />}
              {!isLoading && !error && conversations.length === 0 && (
                <EmptyState
                  icon={<MessageSquare size={28} />}
                  heading="No conversations"
                  sub="Messages will appear here once sync runs."
                />
              )}
              {!isLoading && !error && conversations.length > 0 && (
                <>
                  <ConvCount>{conversations.length} conversation{conversations.length !== 1 ? 's' : ''}</ConvCount>
                  <ConversationList
                    conversations={conversations}
                    selectedId={selectedId}
                    onSelect={setSelectedId}
                  />
                </>
              )}
            </>
          )}
        </SidePanel>
        <Content>
          {selected ? (
            <ThreadView
              conversationId={selected.id}
              displayName={(selected.displayName || selected.participants[0]) ?? 'Thread'}
              {...(trimmedQuery ? { searchQuery: trimmedQuery } : {})}
              {...(idParam ? { focusMessageId: idParam } : {})}
            />
          ) : (
            <EmptyState
              icon={<MessageSquare size={36} />}
              heading="Select a conversation"
              sub="Choose a thread from the left panel."
            />
          )}
        </Content>
      </Body>
    </Root>
  );
}
