import { useEffect, useState, type ReactElement } from 'react';
import styled from '@lilith/ui-styled-components';
import { MapPin, MessageSquare, Search, User, X, ExternalLink } from 'lucide-react';
import { useNavigate } from '@lilith/ui-router';
import { useUnifiedSearch } from '@/hooks/useSearch';
import { useThread } from '@/hooks/useMessages';
import { EmptyState } from '@/components/EmptyState';
import { PageError } from '@/components/PageError';
import type { UnifiedSearchHit, Message } from '@/types';
import { GEO_LOCATIONS, resolveLocation } from './locations';

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

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

const Sub = styled.span`
  font-size: 12px;
  font-weight: 400;
  color: #8a8a9a;
`;

const SearchBar = styled.div`
  padding: 12px 16px;
  border-bottom: 1px solid #2a2a38;
  background: #0d0d14;
  display: flex;
  align-items: center;
  gap: 8px;
`;

const SearchInput = styled.input`
  flex: 1;
  background: #13131a;
  border: 1px solid #2a2a38;
  border-radius: 6px;
  color: #e0e0f0;
  font-size: 13px;
  padding: 6px 10px;
  outline: none;

  &::placeholder {
    color: #555566;
  }

  &:focus {
    border-color: rgba(201, 168, 76, 0.4);
  }
`;

const ClearBtn = styled.button`
  background: none;
  border: none;
  color: #8a8a9a;
  cursor: pointer;
  padding: 2px;
  display: flex;
  align-items: center;

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

const LocationBar = styled.div`
  display: flex;
  gap: 6px;
  padding: 10px 16px 8px;
  background: #0d0d14;
  flex-wrap: wrap;
  align-items: center;
`;

const LocationLabel = styled.span`
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #6a6a7a;
  margin-right: 4px;
`;

const LocationPill = styled.button<{ $active: boolean }>`
  font-size: 12px;
  font-weight: 600;
  padding: 4px 12px;
  border-radius: 6px;
  border: 1px solid ${({ $active }) => ($active ? '#c9a84c' : '#2a2a38')};
  background: ${({ $active }) => ($active ? 'rgba(201,168,76,0.16)' : 'transparent')};
  color: ${({ $active }) => ($active ? '#c9a84c' : '#b0b0c0')};
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 5px;

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

const Chips = styled.div`
  display: flex;
  gap: 6px;
  padding: 4px 16px 8px;
  border-bottom: 1px solid #2a2a38;
  background: #0d0d14;
  flex-wrap: wrap;
`;

const Chip = styled.button<{ $active: boolean }>`
  font-size: 11px;
  padding: 3px 9px;
  border-radius: 999px;
  border: 1px solid ${({ $active }) => ($active ? '#c9a84c' : '#2a2a38')};
  background: ${({ $active }) => ($active ? 'rgba(201,168,76,0.12)' : 'transparent')};
  color: ${({ $active }) => ($active ? '#c9a84c' : '#b0b0c0')};
  cursor: pointer;

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

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

const Results = styled.div`
  flex: 1;
  overflow-y: auto;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 20px;
`;

const Section = styled.section``;

const SectionTitle = styled.div`
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #8a8a9a;
  margin-bottom: 8px;
  display: flex;
  align-items: center;
  gap: 6px;
`;

const HitList = styled.div`
  display: flex;
  flex-direction: column;
  gap: 8px;
`;

const HitCard = styled.div`
  background: #13131a;
  border: 1px solid #2a2a38;
  border-radius: 6px;
  padding: 10px 12px;
  font-size: 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;

  &:hover {
    border-color: rgba(201,168,76,0.3);
  }
`;

const HitHeader = styled.div`
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
`;

const HitWho = styled.span`
  font-weight: 600;
  color: #e0e0f0;
`;

const FromMeBadge = styled.span`
  font-size: 9px;
  font-weight: 700;
  padding: 1px 5px;
  border-radius: 3px;
  background: rgba(201,168,76,0.2);
  color: #c9a84c;
  letter-spacing: 0.03em;
`;

const HitSnippet = styled.div`
  color: #b0b0c0;
  line-height: 1.35;
  mark {
    background: rgba(201,168,76,0.3);
    color: #f0e0b0;
    padding: 0 1px;
    border-radius: 2px;
  }
`;

const HitMeta = styled.div`
  font-size: 10px;
  color: #8a8a9a;
`;

const ActionBtn = styled.button`
  align-self: flex-start;
  font-size: 11px;
  padding: 4px 8px;
  border: 1px solid #2a2a38;
  border-radius: 4px;
  background: transparent;
  color: #c9a84c;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 4px;

  &:hover {
    background: rgba(201,168,76,0.08);
    border-color: #c9a84c;
  }
`;

const ReviewPanel = styled.div`
  width: 380px;
  border-left: 1px solid #2a2a38;
  background: #0d0d14;
  display: flex;
  flex-direction: column;
  overflow: hidden;
`;

const ReviewHeader = styled.div`
  padding: 12px 16px;
  border-bottom: 1px solid #2a2a38;
  font-size: 12px;
  font-weight: 600;
  color: #e0e0f0;
  display: flex;
  align-items: center;
  gap: 8px;
`;

const ReviewBody = styled.div`
  flex: 1;
  overflow-y: auto;
  padding: 12px 16px;
  font-size: 12px;
`;

const Stat = styled.div`
  margin: 8px 0;
  padding: 8px;
  background: #13131a;
  border-radius: 4px;
`;

const Note = styled.div`
  font-size: 11px;
  color: #8a8a9a;
  padding: 12px 16px;
  border-top: 1px solid #2a2a38;
  line-height: 1.4;
`;

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

const DEVICE_ID: string | undefined = undefined;

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 hitKey(hit: UnifiedSearchHit): string {
  if (hit.surface === 'contact') return `c-${hit.hit.contact.id}`;
  if (hit.surface === 'message' || hit.surface === 'mail') return `m-${hit.hit.message.id}`;
  return `e-${hit.hit.event.id}`;
}

export function GeoTab(): ReactElement {
  const [locationId, setLocationId] = useState(GEO_LOCATIONS[0].id);
  const location = resolveLocation(locationId);

  const [input, setInput] = useState(location.aliases[0]);
  const [debounced, setDebounced] = useState(location.aliases[0]);
  const [reviewConvId, setReviewConvId] = useState<string | null>(null);

  const navigate = useNavigate();
  const searchOpts = DEVICE_ID ? { deviceId: DEVICE_ID } : {};
  const { data, isLoading, error } = useUnifiedSearch(debounced, searchOpts);

  const threadQ = useThread(reviewConvId);

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

  function selectLocation(id: string): void {
    const next = resolveLocation(id);
    setLocationId(next.id);
    setInput(next.aliases[0]);
    setDebounced(next.aliases[0]);
    setReviewConvId(null);
  }

  function activateChip(q: string): void {
    setInput(q);
    setDebounced(q);
    setReviewConvId(null);
  }

  const grouped = {
    contact: [] as Extract<UnifiedSearchHit, { surface: 'contact' }>[ ],
    message: [] as Extract<UnifiedSearchHit, { surface: 'message' }>[ ],
    mail: [] as Extract<UnifiedSearchHit, { surface: 'mail' }>[ ],
    calendar: [] as Extract<UnifiedSearchHit, { surface: 'calendar' }>[ ],
  };

  if (data) {
    for (const h of data.results) {
      if (h.surface === 'contact') grouped.contact.push(h);
      else if (h.surface === 'message') grouped.message.push(h);
      else if (h.surface === 'mail') grouped.mail.push(h);
      else if (h.surface === 'calendar') grouped.calendar.push(h);
    }
  }

  const messageHits = [...grouped.message, ...grouped.mail];

  const threadMessages: Message[] = threadQ.data ?? [];
  const myReplies = threadMessages.filter((m) => m.isFromMe);
  const theirMessages = threadMessages.filter((m) => !m.isFromMe);

  function openThread(hit: UnifiedSearchHit): void {
    if (hit.surface === 'contact') {
      const handle = hit.hit.contact.handle;
      navigate(`/messages?handle=${encodeURIComponent(handle)}&q=${encodeURIComponent(debounced)}`);
      return;
    }
    if (hit.surface === 'message' || hit.surface === 'mail') {
      const convId = hit.hit.message.conversationId;
      const msgId = hit.hit.message.id;
      navigate(`/messages?conv=${encodeURIComponent(convId)}&q=${encodeURIComponent(debounced)}&id=${encodeURIComponent(msgId)}`);
      // Also offer thread review
      setReviewConvId(convId);
    }
  }

  function startReview(convId: string): void {
    setReviewConvId(convId);
  }

  return (
    <Root>
      <PageHeading>
        <span>
          <MapPin size={18} style={{ verticalAlign: 'middle', marginRight: 8 }} />
          Geo Review
        </span>
        <Sub>Find people by area / location mentions • Verify replies</Sub>
      </PageHeading>

      <LocationBar>
        <LocationLabel>Location</LocationLabel>
        {GEO_LOCATIONS.map((loc) => (
          <LocationPill
            key={loc.id}
            $active={loc.id === locationId}
            onClick={() => selectLocation(loc.id)}
          >
            <MapPin size={11} /> {loc.label}
          </LocationPill>
        ))}
      </LocationBar>

      <SearchBar>
        <Search size={14} color="#6a6a7a" />
        <SearchInput
          type="search"
          placeholder="Search austin, 512, houston, 713, etc."
          value={input}
          onChange={(e) => setInput(e.target.value)}
          aria-label="Geo search query"
        />
        {input && (
          <ClearBtn onClick={() => { setInput(''); setDebounced(''); }} aria-label="Clear">
            <X size={14} />
          </ClearBtn>
        )}
      </SearchBar>

      <Chips>
        {location.aliases.map((c) => (
          <Chip key={c} $active={debounced.toLowerCase() === c.toLowerCase()} onClick={() => activateChip(c)}>
            {c}
          </Chip>
        ))}
        <Chip $active={false} onClick={() => { setInput(''); setDebounced(''); setReviewConvId(null); }}>
          Clear
        </Chip>
      </Chips>

      <Body>
        <Results>
          {isLoading && <SpinnerWrap aria-live="polite">Searching…</SpinnerWrap>}
          {error && <PageError message="Search failed" />}

          {!isLoading && data && data.results.length === 0 && (
            <EmptyState
              icon={<MapPin size={28} />}
              heading="No matches"
              sub="Try broadening with the chips above or check Mail tab too."
            />
          )}

          {!isLoading && data && data.results.length > 0 && (
            <>
              <div style={{ fontSize: 12, color: '#8a8a9a', marginBottom: 8 }}>
                {data.results.length} holistic results for “{debounced}” (messages + mail + contacts + calendar)
              </div>

              {grouped.contact.length > 0 && (
                <Section>
                  <SectionTitle>
                    <User size={12} /> Contacts ({grouped.contact.length})
                  </SectionTitle>
                  <HitList>
                    {grouped.contact.map((hit) => {
                      const c = hit.hit.contact;
                      return (
                        <HitCard key={hitKey(hit)}>
                          <HitHeader>
                            <HitWho>{c.displayName || c.handle}</HitWho>
                            <ActionBtn onClick={() => openThread(hit)}>
                              Open <ExternalLink size={11} />
                            </ActionBtn>
                          </HitHeader>
                          <HitMeta>
                            {hit.hit.matchField} match • {c.handle}
                            {c.phoneNumbers?.[0] ? ` • ${c.phoneNumbers[0]}` : ''}
                          </HitMeta>
                        </HitCard>
                      );
                    })}
                  </HitList>
                </Section>
              )}

              {messageHits.length > 0 && (
                <Section>
                  <SectionTitle>
                    <MessageSquare size={12} /> Messages &amp; Mail ({messageHits.length})
                  </SectionTitle>
                  <HitList>
                    {messageHits.map((hit) => {
                      const m = hit.hit.message;
                      const isMe = m.isFromMe;
                      const convId = m.conversationId;
                      return (
                        <HitCard key={hitKey(hit)}>
                          <HitHeader>
                            <HitWho>
                              {isMe ? 'You' : m.fromHandle || 'Unknown'}
                              {hit.surface === 'mail' && ' (mail)'}
                            </HitWho>
                            {isMe && <FromMeBadge>from you</FromMeBadge>}
                          </HitHeader>
                          <HitSnippet>{renderSnippet(hit.hit.snippet)}</HitSnippet>
                          <HitMeta>
                            {new Date(m.sentAt).toLocaleDateString()} · conv {convId.slice(0, 8)}…
                          </HitMeta>
                          <div style={{ display: 'flex', gap: 6, marginTop: 4 }}>
                            <ActionBtn onClick={() => openThread(hit)}>
                              Open thread <ExternalLink size={11} />
                            </ActionBtn>
                            <ActionBtn onClick={() => startReview(convId)}>
                              Review replies in thread
                            </ActionBtn>
                          </div>
                        </HitCard>
                      );
                    })}
                  </HitList>
                </Section>
              )}

              {grouped.calendar.length > 0 && (
                <Section>
                  <SectionTitle>Calendar ({grouped.calendar.length})</SectionTitle>
                  <HitList>
                    {grouped.calendar.map((hit) => (
                      <HitCard key={hitKey(hit)}>
                        <HitHeader>
                          <HitWho>{hit.hit.event.title}</HitWho>
                        </HitHeader>
                        <HitSnippet>{renderSnippet(hit.hit.snippet)}</HitSnippet>
                      </HitCard>
                    ))}
                  </HitList>
                </Section>
              )}
            </>
          )}

          <Note>
            This page runs the same holistic unified search as the header (RRF across iMessage, Mail, Contacts, Calendar).
            Location / area matching is fuzzy — try the chips for area codes, cities, nicknames, etc. To confirm you <strong>replied</strong> to someone, use “Review replies in thread” below or open the thread and look for your outgoing (gold) bubbles in the history. The search surfaces mentions; full reply status requires looking at the actual conversation thread.
          </Note>
        </Results>

        <ReviewPanel>
          <ReviewHeader>
            <MessageSquare size={14} /> Thread reply reviewer
          </ReviewHeader>
          <ReviewBody>
            {!reviewConvId && (
              <div style={{ color: '#8a8a9a', fontSize: 12 }}>
                Click “Review replies in thread” on any message hit above to load the full conversation here and count your replies.
              </div>
            )}

            {reviewConvId && threadQ.isLoading && <SpinnerWrap>Loading thread…</SpinnerWrap>}
            {reviewConvId && threadQ.error && <PageError message="Failed to load thread" />}

            {reviewConvId && threadQ.data && (
              <>
                <Stat>
                  Conversation: <code>{reviewConvId}</code><br />
                  Total messages in thread: <strong>{threadMessages.length}</strong><br />
                  Your outgoing messages: <strong style={{ color: '#c9a84c' }}>{myReplies.length}</strong><br />
                  Their messages: {theirMessages.length}
                </Stat>

                {myReplies.length > 0 ? (
                  <div>
                    <div style={{ margin: '8px 0 4px', fontWeight: 600, fontSize: 11 }}>Your replies (newest first):</div>
                    {myReplies.slice(0, 5).reverse().map((m, idx) => (
                      <div key={idx} style={{ marginBottom: 6, padding: 6, background: '#1c1c26', borderRadius: 4 }}>
                        {m.body ? m.body.slice(0, 140) : '(no text)'}
                        {m.hasAttachments && ' 📎'}
                        <div style={{ fontSize: 10, color: '#8a8a9a', marginTop: 2 }}>
                          {new Date(m.sentAt).toLocaleString()}
                        </div>
                      </div>
                    ))}
                    {myReplies.length > 5 && <div style={{ fontSize: 10, color: '#8a8a9a' }}>+ {myReplies.length - 5} more</div>}
                  </div>
                ) : (
                  <div style={{ color: '#c9a84c', fontSize: 12 }}>No outgoing messages found in this thread from you.</div>
                )}

                <ActionBtn style={{ marginTop: 12 }} onClick={() => navigate(`/messages?conv=${encodeURIComponent(reviewConvId)}&q=${encodeURIComponent(debounced)}`)}>
                  Open full thread in Messages tab
                </ActionBtn>
              </>
            )}
          </ReviewBody>
          <Note style={{ fontSize: 10 }}>
            Use this to quickly verify 2-way communication for any location-related thread the search surfaced.
          </Note>
        </ReviewPanel>
      </Body>
    </Root>
  );
}
