# Search Integration

Complete examples for implementing business search in your application.

## Basic Search

### TypeScript/JavaScript

```typescript
import { AIDPClient } from '@aidp/sdk';

const client = new AIDPClient({
  apiKey: process.env.AIDP_API_KEY,
});

async function searchBusinesses(query: string) {
  try {
    const results = await client.search({
      query,
      location: { lat: 45.5231, lon: -122.6765, distance: '5km' },
      limit: 10,
    });

    console.log(`AI Response: ${results.data.response}`);
    console.log(`Found ${results.data.total} businesses`);

    results.data.businesses.forEach((business) => {
      console.log(`- ${business.name} (${business.distance}m away)`);
    });

    return results.data.businesses;
  } catch (error) {
    console.error('Search failed:', error.message);
    throw error;
  }
}

// Usage
const businesses = await searchBusinesses('coffee shops with wifi');
```

### Python

```python
from aidp import AIDPClient
import os

client = AIDPClient(api_key=os.environ['AIDP_API_KEY'])

def search_businesses(query: str):
    try:
        results = client.search(
            query=query,
            location={'lat': 45.5231, 'lon': -122.6765, 'distance': '5km'},
            limit=10
        )

        print(f"AI Response: {results.data.response}")
        print(f"Found {results.data.total} businesses")

        for business in results.data.businesses:
            print(f"- {business.name} ({business.distance}m away)")

        return results.data.businesses
    except Exception as e:
        print(f"Search failed: {str(e)}")
        raise

# Usage
businesses = search_businesses('coffee shops with wifi')
```

***

## Location-Based Search

### Get User's Location (Browser)

```javascript
async function searchNearby(query) {
  return new Promise((resolve, reject) => {
    navigator.geolocation.getCurrentPosition(
      async (position) => {
        const results = await client.search({
          query,
          location: {
            lat: position.coords.latitude,
            lon: position.coords.longitude,
            distance: '5km',
          },
        });
        resolve(results.data.businesses);
      },
      (error) => reject(error)
    );
  });
}

// Usage
const nearbyBusinesses = await searchNearby('restaurants');
```

### Search Multiple Locations

```typescript
async function searchMultipleLocations(
  query: string,
  locations: Array<{ lat: number; lon: number }>
) {
  const promises = locations.map((location) =>
    client.search({ query, location: { ...location, distance: '5km' } })
  );

  const results = await Promise.all(promises);

  return results.map((result, index) => ({
    location: locations[index],
    businesses: result.data.businesses,
  }));
}

// Usage
const locations = [
  { lat: 45.5231, lon: -122.6765 }, // Portland
  { lat: 47.6062, lon: -122.3321 }, // Seattle
  { lat: 37.7749, lon: -122.4194 }, // San Francisco
];

const allResults = await searchMultipleLocations('coffee shops', locations);
```

***

## Autocomplete Search

### React Component

```typescript
import { useState, useEffect } from 'react';
import { AIDPClient } from '@aidp/sdk';

const client = new AIDPClient({ apiKey: process.env.NEXT_PUBLIC_AIDP_API_KEY });

export function SearchAutocomplete() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    if (!query) {
      setResults([]);
      return;
    }

    const timeout = setTimeout(async () => {
      setLoading(true);
      try {
        const response = await client.search({
          query,
          limit: 5
        });
        setResults(response.data.businesses);
      } catch (error) {
        console.error('Search failed:', error);
      } finally {
        setLoading(false);
      }
    }, 300); // Debounce

    return () => clearTimeout(timeout);
  }, [query]);

  return (
    <div>
      <input
        type="text"
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder="Search businesses..."
      />
      {loading && <div>Loading...</div>}
      <ul>
        {results.map(business => (
          <li key={business.id}>
            <strong>{business.name}</strong>
            <p>{business.description}</p>
          </li>
        ))}
      </ul>
    </div>
  );
}
```

### Vanilla JavaScript

```html
<input id="search" type="text" placeholder="Search..." />
<div id="suggestions"></div>

<script>
  const client = new AIDP.Client({ apiKey: 'your-api-key' });
  let timeout;

  document.getElementById('search').addEventListener('input', (e) => {
    clearTimeout(timeout);
    const query = e.target.value;

    if (!query) {
      document.getElementById('suggestions').innerHTML = '';
      return;
    }

    timeout = setTimeout(async () => {
      const results = await client.search({ query, limit: 5 });

      const html = results.data.businesses
        .map(
          (b) => `
          <div class="suggestion">
            <strong>${b.name}</strong>
            <p>${b.description}</p>
          </div>
        `
        )
        .join('');

      document.getElementById('suggestions').innerHTML = html;
    }, 300);
  });
</script>
```

***

## Search with Filters

```typescript
interface SearchFilters {
  query: string;
  category?: string;
  verified?: boolean;
  minRating?: number;
  maxDistance?: string;
}

async function advancedSearch(filters: SearchFilters) {
  const results = await client.search({
    query: filters.query,
    category: filters.category,
    location: {
      lat: 45.5231,
      lon: -122.6765,
      distance: filters.maxDistance || '10km',
    },
  });

  // Client-side filtering for additional criteria
  let businesses = results.data.businesses;

  if (filters.minRating) {
    businesses = businesses.filter((b) => b.averageRating >= filters.minRating);
  }

  return businesses;
}

// Usage
const filteredResults = await advancedSearch({
  query: 'restaurants',
  category: 'restaurants',
  minRating: 4.0,
  maxDistance: '5km',
});
```

***

## Pagination

### Load More Pattern

```typescript
class SearchPaginator {
  private offset = 0;
  private readonly limit = 20;
  private hasMore = true;

  async loadMore(query: string) {
    if (!this.hasMore) return [];

    const results = await client.search({
      query,
      limit: this.limit,
      offset: this.offset,
    });

    this.hasMore = results.data.pagination.hasMore;
    this.offset += this.limit;

    return results.data.businesses;
  }

  reset() {
    this.offset = 0;
    this.hasMore = true;
  }
}

// Usage
const paginator = new SearchPaginator();
const firstPage = await paginator.loadMore('coffee shops');
const secondPage = await paginator.loadMore('coffee shops');
```

### Infinite Scroll (React)

```typescript
import { useState, useEffect, useRef } from 'react';

export function InfiniteSearchResults({ query }: { query: string }) {
  const [businesses, setBusinesses] = useState([]);
  const [loading, setLoading] = useState(false);
  const [hasMore, setHasMore] = useState(true);
  const offset = useRef(0);
  const observer = useRef<IntersectionObserver>();

  const lastBusinessRef = useCallback((node: HTMLDivElement) => {
    if (loading) return;
    if (observer.current) observer.current.disconnect();

    observer.current = new IntersectionObserver(entries => {
      if (entries[0].isIntersecting && hasMore) {
        loadMore();
      }
    });

    if (node) observer.current.observe(node);
  }, [loading, hasMore]);

  const loadMore = async () => {
    setLoading(true);
    const results = await client.search({
      query,
      limit: 20,
      offset: offset.current
    });

    setBusinesses(prev => [...prev, ...results.data.businesses]);
    setHasMore(results.data.pagination.hasMore);
    offset.current += 20;
    setLoading(false);
  };

  return (
    <div>
      {businesses.map((business, index) => (
        <div
          key={business.id}
          ref={index === businesses.length - 1 ? lastBusinessRef : null}
        >
          <h3>{business.name}</h3>
          <p>{business.description}</p>
        </div>
      ))}
      {loading && <div>Loading...</div>}
    </div>
  );
}
```

***

## Full-Stack Example

### Next.js API Route

```typescript
// app/api/search/route.ts
import { AIDPClient } from '@aidp/sdk';
import { NextRequest, NextResponse } from 'next/server';

const client = new AIDPClient({
  apiKey: process.env.AIDP_API_KEY!,
});

export async function POST(request: NextRequest) {
  try {
    const body = await request.json();
    const { query, location, category, limit, offset } = body;

    const results = await client.search({
      query,
      location,
      category,
      limit: limit || 10,
      offset: offset || 0,
    });

    return NextResponse.json(results);
  } catch (error) {
    return NextResponse.json(
      { error: error.message, code: error.code },
      { status: error.status || 500 }
    );
  }
}
```

### Frontend Component

```typescript
// components/BusinessSearch.tsx
'use client';

import { useState } from 'react';

export function BusinessSearch() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);
  const [loading, setLoading] = useState(false);

  const handleSearch = async () => {
    setLoading(true);
    try {
      const response = await fetch('/api/search', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          query,
          location: { lat: 45.5231, lon: -122.6765, distance: '5km' }
        })
      });

      const data = await response.json();
      setResults(data.data.businesses);
    } catch (error) {
      console.error('Search failed:', error);
    } finally {
      setLoading(false);
    }
  };

  return (
    <div>
      <input
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        onKeyPress={(e) => e.key === 'Enter' && handleSearch()}
      />
      <button onClick={handleSearch} disabled={loading}>
        {loading ? 'Searching...' : 'Search'}
      </button>
      <div>
        {results.map(business => (
          <div key={business.id}>
            <h3>{business.name}</h3>
            <p>{business.description}</p>
            <p>{business.distance}m away</p>
          </div>
        ))}
      </div>
    </div>
  );
}
```

***

## Error Handling

```typescript
async function robustSearch(query: string) {
  try {
    const results = await client.search({ query });
    return { success: true, data: results.data };
  } catch (error) {
    if (error.code === 'RATE_LIMIT_EXCEEDED') {
      // Wait and retry
      await new Promise((resolve) => setTimeout(resolve, error.retryAfter * 1000));
      return robustSearch(query);
    } else if (error.code === 'VALIDATION_ERROR') {
      return { success: false, error: 'Invalid search parameters', details: error.details };
    } else if (error.code === 'AUTHENTICATION_ERROR') {
      return { success: false, error: 'Authentication failed. Check your API key.' };
    } else {
      return { success: false, error: 'An unexpected error occurred.' };
    }
  }
}
```

***

**Next**: [Analytics Examples →](https://amistan.gitbook.io/aidp-docs/for-developers/examples/analytics)
