/**
 * Mapping of common street/address keywords to their abbreviations and vice-versa.
 * Each inner array contains [long_form, short_abbreviation]
 * Used for expanding search queries to include both full and abbreviated forms.
 */
const keywords = [
  ['road', 'rd'], // road -> rd and vice-versa
  ['street', 'st'], // street -> st
  ['avenue', 'ave'], // avenue -> ave
  ['boulevard', 'blvd'], // boulevard -> blvd
  ['drive', 'dr'], // drive -> dr
  ['lane', 'ln'], // lane -> ln
  ['crescent', 'cr'], // crescent -> cr
  ['court', 'ct'], // court -> ct
  ['circle', 'cir'], // circle -> cir
  ['place', 'pl'], // place -> pl
  ['square', 'sq'], // square -> sq
  ['terrace', 'ter'], // terrace -> ter
  ['way', 'wy'], // way -> wy
  ['trail', 'trl'], // trail -> trl
  ['parkway', 'pkwy'], // parkway -> pkwy
  ['park', 'pk'], // park -> pk
  ['gardens', 'gdns'], // gardens -> gdns
  ['hill', 'hl'], // hill -> hl
  ['heights', 'hts'], // heights -> hts
  ['ridge', 'rdg'], // ridge -> rdg
  ['view', 'vw'], // view -> vw
];

/**
 * Processes geographical names (typically addresses) to expand search terms
 * by including both full and abbreviated forms of street keywords.
 *
 * This function:
 * 1. Cleans the input by removing special characters
 * 2. Splits into individual words
 * 3. Expands street keywords (e.g., "street" becomes both "street" and "st")
 * 4. Executes a callback function for each processed word
 *
 * @param geoName - The geographical name/address to process (e.g., "Main Street")
 * @param callback - Function to call for each processed word
 *
 * @example
 * // Searching for "Main Street" would call callback with: "Main", "Street", "st"
 * bucketFilter("Main Street, Apt 5", (word) => console.log(word));
 * // Output: "Main", "Street", "st", "Apt", "5"
 *
 * @example
 * // Searching for "123 Oak Rd" would call callback with: "123", "Oak", "Rd", "Road"
 * bucketFilter("123 Oak Rd.", (word) => console.log(word));
 * // Output: "123", "Oak", "Rd", "Road"
 *
 * @example
 * // With empty/null input - gracefully handles undefined
 * bucketFilter(null, (word) => console.log(word));
 * // No output - safely handles null
 */
export const bucketFilter = (geoName: string, callback: any): void => {
  // Remove all special characters except alphanumeric and spaces
  // Optional chaining (?.) safely handles null/undefined input
  // Then split into individual words by space
  const words = geoName?.replace(/[^a-zA-Z0-9 ]/g, '')?.split(' ') || [];

  // Array to store transformed words (original + expanded keywords)
  const transformedWords: string[] = [];

  // Process each word from the input
  words.forEach((word) => {
    // Always include the original word
    transformedWords.push(word);

    // Check if this word matches any known street keywords
    keywords.forEach(([primary, secondary]) => {
      const lowerWord = word.toLowerCase();

      if (lowerWord === primary) {
        // If word matches a long form (e.g., "street"), add abbreviation (e.g., "st")
        transformedWords.push(secondary);
      } else if (lowerWord === secondary) {
        // If word matches an abbreviation (e.g., "rd"), add long form (e.g., "road")
        transformedWords.push(primary);
      }
    });
  });

  // Execute callback for each non-empty transformed word
  transformedWords.forEach((word) => {
    // Skip empty strings that might result from multiple spaces
    if (word !== '') {
      callback(word);
    }
  });
};

/**
 * Usage in search scenarios:
 *
 * // When a user searches for "Maple Street Apartments":
 * // The search would match documents containing:
 * // - "Maple Street Apartments" (exact match)
 * // - "Maple St Apartments" (abbreviation expansion)
 * // - "Maple Street" (partial match with full form)
 * // - "Maple St" (partial match with abbreviation)
 *
 * // Implementation example:
 * const searchTerms = [];
 * bucketFilter("123 Elm Street", (term) => searchTerms.push(term));
 * // searchTerms = ['123', 'Elm', 'Street', 'st']
 *
 * // Then use searchTerms in database query:
 * // SELECT * FROM addresses WHERE
 * //   address ILIKE '%123%' AND
 * //   (address ILIKE '%Elm%' AND
 * //    (address ILIKE '%Street%' OR address ILIKE '%st%'))
 */
