import { useEffect, useRef, useState, type ReactElement } from 'react';
import { useNavigate, useSearchParams } from '@lilith/ui-router';
import styled from '@lilith/ui-styled-components';
import { Search, X, MessageSquare, Mail, Calendar, User } from 'lucide-react';
import { useUnifiedSearch } from '@/hooks/useSearch';
import type { UnifiedSearchHit } from '@/types';

const DEBOUNCE_MS = 200;

const Wrap = styled.div`
  position: relative;
  padding: 12px 12px 8px;
  border-bottom: 1px solid #2a2a38;
`;

const InputRow = styled.div`
  position: relative;
`;

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

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

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

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

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

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

const Panel = styled.div`
  position: absolute;
  top: calc(100% + 4px);
  left: 8px;
  right: 8px;
  background: #0d0d14;
  border: 1px solid #2a2a38;
  border-radius: 8px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6);
  z-index: 500;
  max-height: 480px;
  overflow-y: auto;
`;

const SurfaceGroup = styled.div``;

const SurfaceLabel = styled.div`
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 12px 4px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  color: #6a6a7a;
  text-transform: uppercase;
`;

const HitRow = styled.button`
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 6px 12px;
  background: none;
  border: none;
  text-align: left;
  cursor: pointer;
  color: #e0e0f0;

  &:hover {
    background: #1c1c26;
  }
`;

const HitTitle = styled.div`
  font-size: 12px;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
`;

const HitSnippet = styled.div`
  font-size: 11px;
  color: #8a8a9a;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;

  mark {
    background: rgba(201, 168, 76, 0.25);
    color: #c9a84c;
    border-radius: 2px;
    padding: 0 1px;
  }
`;

const StatusRow = styled.div`
  padding: 12px;
  font-size: 12px;
  color: #6a6a7a;
  text-align: center;
`;

const SURFACE_META = {
  contact: { label: 'Contacts', icon: <User size={11} />, route: '/messages' },
  message: { label: 'Messages', icon: <MessageSquare size={11} />, route: '/messages' },
  mail: { label: 'Mail', icon: <Mail size={11} />, route: '/mail' },
  calendar: { label: 'Calendar', icon: <Calendar size={11} />, route: null },
} as const;

function renderSnippet(raw: string): ReactElement {
  const parts = raw.split(/(«[^»]*»)/g);
  return (
    <>
      {parts.map((p, i) =>
        p.startsWith('«') && p.endsWith('»') ? (
          <mark key={i}>{p.slice(1, -1)}</mark>
        ) : (
          <span key={i}>{p}</span>
        ),
      )}
    </>
  );
}

function hitTitle(hit: UnifiedSearchHit): string {
  if (hit.surface === 'contact') {
    return hit.hit.contact.displayName || hit.hit.contact.handle || '(no name)';
  }
  if (hit.surface === 'message' || hit.surface === 'mail') {
    return hit.hit.message.body.slice(0, 60) || '(no text)';
  }
  return hit.hit.event.title || '(untitled)';
}

function hitSnippet(hit: UnifiedSearchHit): string {
  if (hit.surface === 'contact') {
    const { matchField, contact } = hit.hit;
    const primaryHandle = contact.phoneNumbers[0] ?? contact.emails[0] ?? contact.handle;
    return `${matchField} match · ${primaryHandle}`;
  }
  if (hit.surface === 'message' || hit.surface === 'mail') return hit.hit.snippet;
  return hit.hit.snippet;
}

function hitConversationId(hit: UnifiedSearchHit): string | null {
  if (hit.surface === 'contact') return null;
  if (hit.surface === 'message' || hit.surface === 'mail') {
    return hit.hit.message.conversationId;
  }
  return null;
}

function hitMessageId(hit: UnifiedSearchHit): string | null {
  if (hit.surface === 'contact') return null;
  if (hit.surface === 'message' || hit.surface === 'mail') {
    return hit.hit.message.id;
  }
  return null;
}

export function GlobalSearch(): ReactElement {
  const [searchParams] = useSearchParams();
  const initialQ = searchParams.get('q') ?? '';
  const [input, setInput] = useState(initialQ);
  const [debounced, setDebounced] = useState(initialQ);
  const [open, setOpen] = useState(initialQ.length >= 2);
  const navigate = useNavigate();
  const wrapRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const q = searchParams.get('q') ?? '';
    setInput(q);
    setDebounced(q);
    setOpen(q.length >= 2);
  }, [searchParams]);

  useEffect(() => {
    const h = setTimeout(() => setDebounced(input), DEBOUNCE_MS);
    return () => clearTimeout(h);
  }, [input]);

  useEffect(() => {
    setOpen(debounced.trim().length >= 2);
  }, [debounced]);

  useEffect(() => {
    const handler = (e: MouseEvent) => {
      if (wrapRef.current && !wrapRef.current.contains(e.target as Node)) {
        setOpen(false);
      }
    };
    document.addEventListener('mousedown', handler);
    return () => document.removeEventListener('mousedown', handler);
  }, []);

  const { data, isLoading } = useUnifiedSearch(debounced);

  const grouped = {
    contact: [] as UnifiedSearchHit[],
    message: [] as UnifiedSearchHit[],
    mail: [] as UnifiedSearchHit[],
    calendar: [] as UnifiedSearchHit[],
  };
  if (data) {
    for (const h of data.results) grouped[h.surface].push(h);
  }

  function handleHitClick(hit: UnifiedSearchHit) {
    if (hit.surface === 'contact') {
      navigate(`/messages?handle=${encodeURIComponent(hit.hit.contact.handle)}`);
      setOpen(false);
      setInput('');
      return;
    }
    const convId = hitConversationId(hit);
    const msgId = hitMessageId(hit);
    const meta = SURFACE_META[hit.surface];
    if (meta.route && convId) {
      const params = new URLSearchParams({ conv: convId });
      if (debounced.trim()) params.set('q', debounced.trim());
      if (msgId) params.set('id', msgId);
      navigate(`${meta.route}?${params.toString()}`);
    } else if (meta.route) {
      navigate(meta.route);
    }
    setOpen(false);
    setInput('');
  }

  const totalHits = data ? data.results.length : 0;
  const hasResults = totalHits > 0;

  return (
    <Wrap ref={wrapRef}>
      <InputRow>
        <SearchIcon>
          <Search size={12} />
        </SearchIcon>
        <Input
          type="search"
          placeholder="Search everything…"
          value={input}
          onChange={(e) => setInput(e.target.value)}
          onFocus={() => debounced.trim().length >= 2 && setOpen(true)}
          aria-label="Global search"
          aria-expanded={open}
          aria-autocomplete="list"
        />
        {input && (
          <ClearBtn
            type="button"
            aria-label="Clear search"
            onClick={() => {
              setInput('');
              setOpen(false);
            }}
          >
            <X size={11} />
          </ClearBtn>
        )}
      </InputRow>

      {open && (
        <Panel role="listbox" aria-label="Search results">
          {isLoading && <StatusRow>Searching…</StatusRow>}
          {!isLoading && data && !hasResults && (
            <StatusRow>No results for "{debounced}"</StatusRow>
          )}
          {(['contact', 'message', 'mail', 'calendar'] as const).map((surface) => {
            const hits = grouped[surface];
            if (!hits.length) return null;
            const meta = SURFACE_META[surface];
            return (
              <SurfaceGroup key={surface}>
                <SurfaceLabel>
                  {meta.icon}
                  {meta.label}
                </SurfaceLabel>
                {hits.map((hit, i) => (
                  <HitRow
                    key={i}
                    role="option"
                    onClick={() => handleHitClick(hit)}
                    style={meta.route === null ? { cursor: 'default' } : undefined}
                  >
                    <HitTitle>{hitTitle(hit)}</HitTitle>
                    <HitSnippet>{renderSnippet(hitSnippet(hit))}</HitSnippet>
                  </HitRow>
                ))}
              </SurfaceGroup>
            );
          })}
        </Panel>
      )}
    </Wrap>
  );
}
