import React, {
  ChangeEventHandler,
  FormEventHandler,
  RefObject,
  useCallback,
  useMemo,
  useRef,
  useState,
} from 'react';
import {
  Avatar,
  Box,
  Chip,
  config,
  Icon,
  Icons,
  Input,
  Menu,
  MenuItem,
  Spinner,
  Text,
} from 'folds';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { getMxIdLocalPart, getMxIdServer, mxcUrlToHttp } from '../../utils/matrix';
import { UserAvatar } from '../../components/user-avatar';
import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';

// Matches "from:@?anything" anywhere — @ is optional
const FROM_REGEX = /from:@?([^\s:][^\s]*)/gi;
// Matches trailing "from:@?..." so autocomplete fires as the user types
const FROM_TYPING_REGEX = /from:@?([^\s]*)$/i;

type UserSuggestion = {
  userId: string;
  displayName?: string;
  avatarUrl?: string;
};

type SearchInputProps = {
  active?: boolean;
  loading?: boolean;
  searchInputRef: RefObject<HTMLInputElement>;
  onSearch: (term: string) => void;
  onReset: () => void;
  onSenderAdd?: (userId: string) => void;
  recentSearches?: string[];
  onRecentSearch?: (term: string) => void;
  onClearRecentSearches?: () => void;
};
export function SearchInput({
  active,
  loading,
  searchInputRef,
  onSearch,
  onReset,
  onSenderAdd,
  recentSearches,
  onRecentSearch,
  onClearRecentSearches,
}: SearchInputProps) {
  const mx = useMatrixClient();
  const useAuthentication = useMediaAuthentication();
  const inputWrapRef = useRef<HTMLDivElement>(null);

  const [fromQuery, setFromQuery] = useState('');
  const [showSuggestions, setShowSuggestions] = useState(false);
  const [focused, setFocused] = useState(false);
  const [inputEmpty, setInputEmpty] = useState(true);

  // Collect users from room member lists, scored for relevance.
  // Score: same homeserver → +1000, each shared room → +1.
  // This ensures @user:matrix.lotusguild.org ranks above @user:matrix.org.
  const allUsers = useMemo<UserSuggestion[]>(() => {
    const myId = mx.getUserId();
    const myServer = myId ? getMxIdServer(myId) : undefined;

    const map = new Map<string, UserSuggestion & { score: number }>();
    mx.getRooms().forEach((room) => {
      room.getMembers().forEach((member) => {
        if (member.userId === myId) return;
        const existing = map.get(member.userId);
        if (existing) {
          existing.score += 1; // +1 per additional shared room
        } else {
          const homeserver = getMxIdServer(member.userId);
          map.set(member.userId, {
            userId: member.userId,
            displayName: member.name ?? undefined,
            avatarUrl: member.getMxcAvatarUrl() ?? undefined,
            score: myServer && homeserver === myServer ? 1000 : 1,
          });
        }
      });
    });

    return Array.from(map.values()).sort((a, b) => b.score - a.score);
  }, [mx]);

  const suggestedUsers = useMemo(() => {
    if (!showSuggestions) return [];
    const q = fromQuery.toLowerCase();
    return allUsers
      .filter(
        (u) =>
          u.userId.toLowerCase().includes(q) || (u.displayName ?? '').toLowerCase().includes(q),
      )
      .slice(0, 8);
  }, [allUsers, fromQuery, showSuggestions]);

  const closeAutocomplete = useCallback(() => {
    setFromQuery('');
    setShowSuggestions(false);
  }, []);

  const handleUserSelect = useCallback(
    (userId: string) => {
      if (searchInputRef.current) {
        searchInputRef.current.value = searchInputRef.current.value
          .replace(FROM_TYPING_REGEX, '')
          .replace(/\s+/g, ' ')
          .trim();
      }
      closeAutocomplete();
      onSenderAdd?.(userId);
      searchInputRef.current?.focus();
    },
    [searchInputRef, onSenderAdd, closeAutocomplete],
  );

  const handleChange: ChangeEventHandler<HTMLInputElement> = (evt) => {
    const value = evt.target.value;
    setInputEmpty(value.trim() === '');
    const match = FROM_TYPING_REGEX.exec(value);
    if (match) {
      setFromQuery(match[1]);
      setShowSuggestions(true);
    } else {
      closeAutocomplete();
    }
  };

  const handleFocus = () => {
    setFocused(true);
  };

  // Close autocomplete when input loses focus — delay so item clicks fire first
  const handleBlur = () => {
    setTimeout(() => {
      closeAutocomplete();
      setFocused(false);
    }, 150);
  };

  const handleRecentClick = (term: string) => {
    if (searchInputRef.current) {
      searchInputRef.current.value = term;
    }
    setInputEmpty(false);
    onRecentSearch?.(term);
  };

  const handleSearchSubmit: FormEventHandler<HTMLFormElement> = (evt) => {
    evt.preventDefault();
    const { searchInput } = evt.target as HTMLFormElement & {
      searchInput: HTMLInputElement;
    };

    const rawValue = searchInput.value.trim();

    // Extract from:user fragments and convert to sender filters
    const fromMatches = [...rawValue.matchAll(FROM_REGEX)];
    fromMatches.forEach((match) => {
      const raw = match[1];
      const userId = raw.startsWith('@') ? raw : `@${raw}`;
      onSenderAdd?.(userId);
    });

    const searchTerm = rawValue.replace(FROM_REGEX, '').replace(/\s+/g, ' ').trim() || undefined;

    // Remove the from: fragments from the visible input
    if (fromMatches.length > 0 && searchInputRef.current) {
      searchInputRef.current.value = searchTerm ?? '';
    }

    // Always trigger search when senders were extracted, even with no body text
    if (fromMatches.length > 0 || searchTerm) {
      onSearch(searchTerm ?? '');
    }
    closeAutocomplete();
  };

  return (
    <Box as="form" direction="Column" gap="100" onSubmit={handleSearchSubmit}>
      <span data-spacing-node />
      <Text size="L400">Search</Text>
      {/* Relative wrapper so the absolute dropdown positions against the input */}
      <Box ref={inputWrapRef} direction="Column" style={{ position: 'relative' }}>
        <Input
          ref={searchInputRef}
          style={{ paddingRight: config.space.S300 }}
          name="searchInput"
          autoFocus
          size="500"
          variant="Background"
          placeholder="Search messages or type from:@user to filter by sender"
          autoComplete="off"
          onChange={handleChange}
          onFocus={handleFocus}
          onBlur={handleBlur}
          before={
            active && loading ? (
              <Spinner variant="Secondary" size="200" />
            ) : (
              <Icon size="200" src={Icons.Search} />
            )
          }
          after={
            active ? (
              <Chip
                key="resetButton"
                type="reset"
                variant="Secondary"
                size="400"
                radii="Pill"
                outlined
                after={<Icon size="50" src={Icons.Cross} />}
                onClick={onReset}
              >
                <Text size="B300">Clear</Text>
              </Chip>
            ) : (
              <Chip type="submit" variant="Primary" size="400" radii="Pill" outlined>
                <Text size="B300">Enter</Text>
              </Chip>
            )
          }
        />
        {suggestedUsers.length > 0 && (
          <div
            style={{
              position: 'absolute',
              top: '100%',
              left: 0,
              right: 0,
              zIndex: 999,
              marginTop: config.space.S100,
            }}
          >
            <Menu variant="Surface" style={{ width: '100%' }}>
              <Box direction="Column" style={{ padding: `${config.space.S100} 0` }}>
                {suggestedUsers.map((user) => {
                  const displayName = user.displayName ?? getMxIdLocalPart(user.userId);
                  const avatarUrl = user.avatarUrl
                    ? (mxcUrlToHttp(mx, user.avatarUrl, useAuthentication, 32, 32, 'crop') ??
                      undefined)
                    : undefined;
                  return (
                    <MenuItem
                      key={user.userId}
                      variant="Surface"
                      size="300"
                      radii="0"
                      onMouseDown={(e: React.MouseEvent) => e.preventDefault()}
                      onClick={() => handleUserSelect(user.userId)}
                      before={
                        <Avatar size="200" radii="Pill">
                          <UserAvatar
                            userId={user.userId}
                            src={avatarUrl}
                            alt={displayName ?? user.userId}
                            renderFallback={() => <Icon size="100" src={Icons.User} filled />}
                          />
                        </Avatar>
                      }
                    >
                      <Box direction="Column" style={{ minWidth: 0 }}>
                        <Text size="T300" truncate>
                          {displayName}
                        </Text>
                        <Text
                          size="T200"
                          truncate
                          priority="300"
                          style={{ fontFamily: 'monospace', fontSize: '0.75em' }}
                        >
                          {user.userId}
                        </Text>
                      </Box>
                    </MenuItem>
                  );
                })}
              </Box>
            </Menu>
          </div>
        )}
        {focused &&
          inputEmpty &&
          suggestedUsers.length === 0 &&
          recentSearches &&
          recentSearches.length > 0 && (
            <div
              style={{
                position: 'absolute',
                top: '100%',
                left: 0,
                right: 0,
                zIndex: 999,
                marginTop: config.space.S100,
              }}
            >
              <Menu variant="Surface" style={{ width: '100%' }}>
                <Box direction="Column" gap="200" style={{ padding: config.space.S300 }}>
                  <Box alignItems="Center" justifyContent="SpaceBetween" gap="200">
                    <Text size="L400">Recent searches</Text>
                    <Chip
                      variant="SurfaceVariant"
                      radii="Pill"
                      onMouseDown={(e: React.MouseEvent) => e.preventDefault()}
                      onClick={() => onClearRecentSearches?.()}
                    >
                      <Text size="T200">Clear</Text>
                    </Chip>
                  </Box>
                  <Box gap="200" wrap="Wrap">
                    {recentSearches.map((term) => (
                      <Chip
                        key={term}
                        variant="SurfaceVariant"
                        radii="Pill"
                        before={<Icon size="50" src={Icons.RecentClock} />}
                        onMouseDown={(e: React.MouseEvent) => e.preventDefault()}
                        onClick={() => handleRecentClick(term)}
                      >
                        <Text size="T200">{term}</Text>
                      </Chip>
                    ))}
                  </Box>
                </Box>
              </Menu>
            </div>
          )}
      </Box>
    </Box>
  );
}
