# Familiar - Self-Hosted AI Companion Platform
# Copyright (c) 2026 George Scott Foley
# ORCID: 0009-0006-4957-0540
# Email: Georgescottfoley@proton.me
# Licensed under the MIT License - see LICENSE file for details

"""
NPI Registry Skill

Search the National Provider Identifier registry for healthcare providers.
Free, no authentication required. Updated daily from NPPES.

API: https://npiregistry.cms.hhs.gov/api/
"""

import logging

from familiar.core.api_cache import cached
from familiar.skills._api_utils import APIError, api_get

logger = logging.getLogger(__name__)

BASE_URL = "https://npiregistry.cms.hhs.gov/api/"
API_VERSION = "2.1"


# ---------------------------------------------------------------------------
# Tool handlers
# ---------------------------------------------------------------------------


def provider_search(data: dict) -> str:
    """Search for healthcare providers by name, specialty, or location."""
    params = {"version": API_VERSION}

    # Build search params from input
    npi = data.get("npi", "")
    if npi:
        params["number"] = npi

    first_name = data.get("first_name", "")
    last_name = data.get("last_name", "")
    org_name = data.get("organization_name", "")
    specialty = data.get("specialty", "")
    city = data.get("city", "")
    state = data.get("state", "")
    zip_code = data.get("zip_code", "")
    limit = min(int(data.get("limit", 10)), 200)

    # Need at least one search criterion
    has_criteria = any([npi, first_name, last_name, org_name, specialty, city, state, zip_code])
    if not has_criteria:
        return (
            "Please provide at least one search criterion: "
            "name, NPI number, specialty, city, state, or zip code."
        )

    if first_name:
        params["first_name"] = first_name
    if last_name:
        params["last_name"] = last_name
    if org_name:
        params["organization_name"] = org_name
    if specialty:
        params["taxonomy_description"] = specialty
    if city:
        params["city"] = city
    if state:
        params["state"] = state
    if zip_code:
        params["postal_code"] = zip_code
    if limit:
        params["limit"] = limit

    try:
        result = _provider_search_cached(
            npi, first_name, last_name, org_name, specialty, city, state, zip_code, limit
        )

        results = result.get("results", [])
        count = result.get("result_count", len(results))

        if not results:
            return "No providers found matching your search criteria."

        lines = [f"Found {count} provider(s):"]
        lines.append("")

        for p in results:
            npi_num = p.get("number", "")
            enum_type = p.get("enumeration_type", "")
            basic = p.get("basic", {})

            if enum_type == "NPI-1":
                name = f"{basic.get('first_name', '')} {basic.get('last_name', '')}".strip()
                credential = basic.get("credential", "")
                if credential:
                    name += f", {credential}"
            else:
                name = basic.get("organization_name", "Unknown Organization")

            # Primary address
            addresses = p.get("addresses", [])
            addr = ""
            for a in addresses:
                if a.get("address_purpose") == "LOCATION":
                    parts = [
                        a.get("city", ""),
                        a.get("state", ""),
                        a.get("postal_code", "")[:5],
                    ]
                    addr = ", ".join(p for p in parts if p)
                    break

            # Taxonomies (specialties)
            taxonomies = p.get("taxonomies", [])
            specs = []
            for t in taxonomies[:3]:
                desc = t.get("desc", "")
                primary = " (primary)" if t.get("primary") else ""
                if desc:
                    specs.append(f"{desc}{primary}")

            lines.append(f"  **{name}** — NPI: {npi_num}")
            if addr:
                lines.append(f"    Location: {addr}")
            if specs:
                lines.append(f"    Specialty: {'; '.join(specs)}")
            lines.append("")

        return "\n".join(lines)

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("NPI search error: %s", e)
        return f"Error searching NPI registry: {e}"


@cached(prefix="npi", ttl=3600)
def _provider_search_cached(
    npi: str,
    first_name: str,
    last_name: str,
    org_name: str,
    specialty: str,
    city: str,
    state: str,
    zip_code: str,
    limit: int,
) -> dict:
    params = {"version": API_VERSION}
    if npi:
        params["number"] = npi
    if first_name:
        params["first_name"] = first_name
    if last_name:
        params["last_name"] = last_name
    if org_name:
        params["organization_name"] = org_name
    if specialty:
        params["taxonomy_description"] = specialty
    if city:
        params["city"] = city
    if state:
        params["state"] = state
    if zip_code:
        params["postal_code"] = zip_code
    if limit:
        params["limit"] = limit

    return api_get(BASE_URL, params=params, service_name="NPI Registry")


# ---------------------------------------------------------------------------
# Tool definitions
# ---------------------------------------------------------------------------

TOOLS = [
    {
        "name": "provider_search",
        "description": (
            "Search the NPI Registry for healthcare providers by name, specialty,"
            " location, or NPI number. Free, no setup required."
            " Use for finding doctors, therapists, clinics, and other providers."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "npi": {
                    "type": "string",
                    "description": "Exact NPI number (10 digits) for direct lookup",
                },
                "first_name": {
                    "type": "string",
                    "description": "Provider first name",
                },
                "last_name": {
                    "type": "string",
                    "description": "Provider last name",
                },
                "organization_name": {
                    "type": "string",
                    "description": "Organization or facility name",
                },
                "specialty": {
                    "type": "string",
                    "description": (
                        "Provider specialty (e.g., 'Family Medicine',"
                        " 'Clinical Psychology', 'Physical Therapy')"
                    ),
                },
                "city": {
                    "type": "string",
                    "description": "City name",
                },
                "state": {
                    "type": "string",
                    "description": "Two-letter state code (e.g., 'NY', 'CA')",
                },
                "zip_code": {
                    "type": "string",
                    "description": "ZIP code",
                },
                "limit": {
                    "type": "integer",
                    "description": "Max results (1-200, default 10)",
                    "default": 10,
                },
            },
        },
        "handler": provider_search,
        "category": "npi",
    },
]
