# 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

"""
Open Referral / 211 Social Services Directory Skill

Search for health, human, and social services using the HSDS standard.

Setup:
    OPEN_REFERRAL_URL=https://api.example-211.org
    OPEN_REFERRAL_API_KEY=your_api_key  (optional — some instances are public)

Standard: https://openreferral.org/
API: HSDS 3.0+ REST endpoints
"""

import logging

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

logger = logging.getLogger(__name__)


def _base_url() -> str:
    return (get_env("OPEN_REFERRAL_URL") or "").rstrip("/")


def _api_key() -> str:
    return get_env("OPEN_REFERRAL_API_KEY") or ""


def _headers() -> dict:
    h: dict = {"Accept": "application/json"}
    key = _api_key()
    if key:
        h["Authorization"] = f"Bearer {key}"
    return h


def _check_config() -> str:
    if not _base_url():
        return (
            "Open Referral not configured.\n"
            "Set OPEN_REFERRAL_URL to your 211/HSDS directory endpoint.\n"
            "Standard: https://openreferral.org/"
        )
    return ""


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


def find_services(data: dict) -> str:
    """Search for social services."""
    err = _check_config()
    if err:
        return err

    query = data.get("query", "").strip()
    if not query:
        return "Please provide a search query (e.g., 'food assistance', 'housing')."

    page = int(data.get("page", 1))
    per_page = min(int(data.get("per_page", 20)), 50)

    try:
        result = _services_cached(query, page, per_page)

        services = result.get("contents", result.get("results", []))
        total = result.get("total_items", result.get("count", len(services)))

        if not services:
            return f"No services found for '{query}'."

        lines = [f"**Services matching '{query}'** ({len(services)} of {total}):", ""]

        for i, svc in enumerate(services, 1):
            name = svc.get("name", "")
            svc_id = svc.get("id", "")
            description = svc.get("description", "")
            org_name = ""
            org = svc.get("organization", {})
            if org:
                org_name = org.get("name", "")

            desc_preview = (description[:80] + "...") if len(description) > 80 else description

            lines.append(f"{i}. **{name}**")
            details = [f"ID: {svc_id}"]
            if org_name:
                details.append(org_name)
            lines.append(f"   {' | '.join(details)}")
            if desc_preview:
                lines.append(f"   {desc_preview}")
            lines.append("")

        return "\n".join(lines)

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


@cached(prefix="hsds_services", ttl=300)
def _services_cached(query: str, page: int, per_page: int) -> dict:
    return api_get(
        f"{_base_url()}/services",
        params={"search": query, "page": page, "per_page": per_page},
        headers=_headers(),
        service_name="Open Referral",
    )


def service_details(data: dict) -> str:
    """Get detailed information about a service."""
    err = _check_config()
    if err:
        return err

    service_id = data.get("service_id", "").strip()
    if not service_id:
        return "Please provide a service_id."

    try:
        result = _service_detail_cached(service_id)

        name = result.get("name", "")
        description = result.get("description", "")
        org = result.get("organization", {})
        org_name = org.get("name", "") if org else ""

        lines = [f"**{name}**", ""]

        if org_name:
            lines.append(f"  Organization: {org_name}")

        if description:
            lines.append(f"  Description: {description[:300]}")

        # Locations
        locations = result.get("service_at_locations", [])
        if locations:
            lines.append("")
            lines.append("**Locations:**")
            for loc_entry in locations[:5]:
                loc = loc_entry.get("location", {})
                loc_name = loc.get("name", "")
                addr = loc.get("address", loc.get("physical_address", {}))
                if isinstance(addr, list) and addr:
                    addr = addr[0]
                if isinstance(addr, dict):
                    street = addr.get("street_address", addr.get("address_1", ""))
                    city = addr.get("city", "")
                    state = addr.get("state", addr.get("state_province", ""))
                    postal = addr.get("postal_code", "")
                    addr_str = f"{street}, {city}, {state} {postal}".strip(", ")
                else:
                    addr_str = str(addr) if addr else ""

                if loc_name or addr_str:
                    lines.append(f"  - {loc_name}: {addr_str}" if loc_name else f"  - {addr_str}")

        # Contacts
        contacts = result.get("contacts", [])
        if contacts:
            lines.append("")
            lines.append("**Contacts:**")
            for c in contacts[:3]:
                c_name = c.get("name", "")
                c_phone = c.get("phone", "")
                c_email = c.get("email", "")
                parts = [p for p in [c_name, c_phone, c_email] if p]
                if parts:
                    lines.append(f"  - {' | '.join(parts)}")

        # Schedules
        schedules = result.get("schedules", result.get("regular_schedule", []))
        if schedules:
            lines.append("")
            lines.append("**Schedule:**")
            for s in schedules[:7]:
                day = s.get("weekday", s.get("day", ""))
                opens = s.get("opens_at", s.get("opens", ""))
                closes = s.get("closes_at", s.get("closes", ""))
                if day:
                    lines.append(f"  - {day}: {opens} - {closes}")

        return "\n".join(lines)

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("Open Referral detail error: %s", e)
        return f"Error fetching service details: {e}"


@cached(prefix="hsds_service_detail", ttl=600)
def _service_detail_cached(service_id: str) -> dict:
    return api_get(
        f"{_base_url()}/services/{service_id}",
        headers=_headers(),
        service_name="Open Referral",
    )


def find_organizations(data: dict) -> str:
    """Search for organizations providing services."""
    err = _check_config()
    if err:
        return err

    query = data.get("query", "").strip()
    if not query:
        return "Please provide a search query."

    per_page = min(int(data.get("per_page", 20)), 50)

    try:
        result = _orgs_cached(query, per_page)

        orgs = result.get("contents", result.get("results", []))
        total = result.get("total_items", result.get("count", len(orgs)))

        if not orgs:
            return f"No organizations found for '{query}'."

        lines = [f"**Organizations matching '{query}'** ({len(orgs)} of {total}):", ""]

        for i, org in enumerate(orgs, 1):
            name = org.get("name", "")
            org_id = org.get("id", "")
            description = org.get("description", "")

            desc_preview = (description[:80] + "...") if len(description) > 80 else description

            lines.append(f"{i}. **{name}** (ID: {org_id})")
            if desc_preview:
                lines.append(f"   {desc_preview}")
            lines.append("")

        return "\n".join(lines)

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("Open Referral org search error: %s", e)
        return f"Error searching organizations: {e}"


@cached(prefix="hsds_orgs", ttl=300)
def _orgs_cached(query: str, per_page: int) -> dict:
    return api_get(
        f"{_base_url()}/organizations",
        params={"search": query, "per_page": per_page},
        headers=_headers(),
        service_name="Open Referral",
    )


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

TOOLS = [
    {
        "name": "find_services",
        "description": "Search for social services (food, housing, healthcare) via Open Referral/211.",
        "input_schema": {
            "type": "object",
            "properties": {
                "query": {
                    "type": "string",
                    "description": "Search query (e.g., 'food assistance', 'housing')",
                },
                "page": {
                    "type": "integer",
                    "description": "Page number (default 1)",
                    "default": 1,
                },
                "per_page": {
                    "type": "integer",
                    "description": "Results per page (1-50, default 20)",
                    "default": 20,
                },
            },
            "required": ["query"],
        },
        "handler": find_services,
        "category": "open_referral",
    },
    {
        "name": "service_details",
        "description": "Get detailed info about a social service: locations, contacts, schedule.",
        "input_schema": {
            "type": "object",
            "properties": {
                "service_id": {
                    "type": "string",
                    "description": "Service ID from find_services",
                },
            },
            "required": ["service_id"],
        },
        "handler": service_details,
        "category": "open_referral",
    },
    {
        "name": "find_organizations",
        "description": "Search for organizations providing social services.",
        "input_schema": {
            "type": "object",
            "properties": {
                "query": {
                    "type": "string",
                    "description": "Search query",
                },
                "per_page": {
                    "type": "integer",
                    "description": "Results per page (1-50, default 20)",
                    "default": 20,
                },
            },
            "required": ["query"],
        },
        "handler": find_organizations,
        "category": "open_referral",
    },
]
