import logging
from typing import Optional

import requests

from open_webui.retrieval.web.main import SearchResult, get_filtered_results

log = logging.getLogger(__name__)

DEFAULT_LINKUP_PARAMS = {
    'url': 'https://api.linkup.so/v1/search',
    'depth': 'standard',
    'outputType': 'sourcedAnswer',
}


def search_linkup(
    api_key: str,
    query: str,
    count: int,
    filter_list: Optional[list[str]] = None,
    params: Optional[dict] = None,
) -> list[SearchResult]:
    """Search using the Linkup Search API.

    ``params`` is forwarded almost verbatim as the JSON body; only ``q``
    and ``maxResults`` are injected automatically.  The special key
    ``url`` (default ``https://api.linkup.so/v1/search``) is popped and
    used as the endpoint.
    """
    if hasattr(api_key, '__str__'):
        api_key = str(api_key)

    merged = {**DEFAULT_LINKUP_PARAMS, **(params or {})}
    api_url = str(merged.pop('url', DEFAULT_LINKUP_PARAMS['url']))

    payload = {**merged, 'q': query, 'maxResults': count}

    try:
        response = requests.post(
            api_url,
            headers={
                'Authorization': f'Bearer {api_key}',
                'Content-Type': 'application/json',
            },
            json=payload,
            timeout=30,
        )
        response.raise_for_status()
        json_response = response.json()

        output_type = merged.get('outputType', 'sourcedAnswer')
        search_results = (
            json_response.get('sources', []) if output_type == 'sourcedAnswer' else json_response.get('results', [])
        )

        if filter_list:
            search_results = get_filtered_results(search_results, filter_list)

        return [
            SearchResult(
                link=r.get('url', ''),
                title=r.get('name') or r.get('title'),
                snippet=r.get('content') or r.get('text') or r.get('snippet'),
            )
            for r in search_results
        ][:count]

    except requests.exceptions.RequestException as e:
        log.error(f'Linkup API request failed: {e}')
        raise Exception(f'Linkup search failed: {str(e)}')
    except Exception as e:
        log.error(f'Error searching Linkup: {e}')
        raise Exception(f'Linkup search error: {str(e)}')
