# 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

"""
HubSpot CRM Skill

Manage contacts, deals, and search the CRM.

Setup:
    HUBSPOT_ACCESS_TOKEN=your_token

Get a token at: https://developers.hubspot.com/
API: https://api.hubapi.com/
"""

import logging

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

logger = logging.getLogger(__name__)

BASE_URL = "https://api.hubapi.com"


def _token() -> str:
    return get_env("HUBSPOT_ACCESS_TOKEN") or ""


def _headers() -> dict:
    return {
        "Authorization": f"Bearer {_token()}",
        "Content-Type": "application/json",
    }


def _check_config() -> str:
    if not _token():
        return (
            "HubSpot not configured.\n"
            "Set HUBSPOT_ACCESS_TOKEN in your environment.\n"
            "Get a token at: https://developers.hubspot.com/"
        )
    return ""


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


def hubspot_contacts(data: dict) -> str:
    """List CRM contacts."""
    err = _check_config()
    if err:
        return err

    limit = min(int(data.get("limit", 20)), 100)

    try:
        result = _contacts_cached(limit)

        contacts = result.get("results", [])
        if not contacts:
            return "No contacts found."

        lines = [f"**HubSpot Contacts** (showing {len(contacts)}):", ""]

        for i, c in enumerate(contacts, 1):
            props = c.get("properties", {})
            name = f"{props.get('firstname', '')} {props.get('lastname', '')}".strip()
            email = props.get("email", "")
            company = props.get("company", "")
            phone = props.get("phone", "")
            cid = c.get("id", "")

            lines.append(f"{i}. **{name or 'Unnamed'}** (ID: {cid})")
            details = []
            if email:
                details.append(email)
            if company:
                details.append(company)
            if phone:
                details.append(phone)
            if details:
                lines.append(f"   {' | '.join(details)}")
            lines.append("")

        return "\n".join(lines)

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("HubSpot contacts error: %s", e)
        return f"Error fetching contacts: {e}"


@cached(prefix="hubspot_contacts", ttl=120)
def _contacts_cached(limit: int) -> dict:
    return api_get(
        f"{BASE_URL}/crm/v3/objects/contacts",
        params={
            "limit": limit,
            "properties": "firstname,lastname,email,company,phone",
        },
        headers=_headers(),
        service_name="HubSpot",
    )


def hubspot_deals(data: dict) -> str:
    """List CRM deals/opportunities."""
    err = _check_config()
    if err:
        return err

    limit = min(int(data.get("limit", 20)), 100)

    try:
        result = _deals_cached(limit)

        deals = result.get("results", [])
        if not deals:
            return "No deals found."

        lines = [f"**HubSpot Deals** (showing {len(deals)}):", ""]

        for i, d in enumerate(deals, 1):
            props = d.get("properties", {})
            name = props.get("dealname", "Unnamed Deal")
            stage = props.get("dealstage", "")
            amount = props.get("amount", "")
            close_date = props.get("closedate", "")[:10] if props.get("closedate") else ""
            did = d.get("id", "")

            lines.append(f"{i}. **{name}** (ID: {did})")
            details = []
            if stage:
                details.append(f"Stage: {stage}")
            if amount:
                details.append(f"${float(amount):,.2f}")
            if close_date:
                details.append(f"Close: {close_date}")
            if details:
                lines.append(f"   {' | '.join(details)}")
            lines.append("")

        return "\n".join(lines)

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("HubSpot deals error: %s", e)
        return f"Error fetching deals: {e}"


@cached(prefix="hubspot_deals", ttl=120)
def _deals_cached(limit: int) -> dict:
    return api_get(
        f"{BASE_URL}/crm/v3/objects/deals",
        params={
            "limit": limit,
            "properties": "dealname,dealstage,amount,closedate",
        },
        headers=_headers(),
        service_name="HubSpot",
    )


def hubspot_add_contact(data: dict) -> str:
    """Create a new CRM contact."""
    err = _check_config()
    if err:
        return err

    email = data.get("email", "").strip()
    if not email:
        return "Please provide an email address."

    firstname = data.get("firstname", "").strip()
    lastname = data.get("lastname", "").strip()
    company = data.get("company", "").strip()
    phone = data.get("phone", "").strip()

    try:
        props = {"email": email}
        if firstname:
            props["firstname"] = firstname
        if lastname:
            props["lastname"] = lastname
        if company:
            props["company"] = company
        if phone:
            props["phone"] = phone

        result = api_post(
            f"{BASE_URL}/crm/v3/objects/contacts",
            json={"properties": props},
            headers=_headers(),
            service_name="HubSpot",
        )

        cid = result.get("id", "")
        return (
            f"**Contact created!**\n\n  ID: {cid}\n  Name: {firstname} {lastname}\n  Email: {email}"
        )

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("HubSpot add contact error: %s", e)
        return f"Error creating contact: {e}"


def hubspot_search(data: dict) -> str:
    """Search CRM contacts and deals."""
    err = _check_config()
    if err:
        return err

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

    obj_type = data.get("object_type", "contacts")

    try:
        result = api_post(
            f"{BASE_URL}/crm/v3/objects/{obj_type}/search",
            json={
                "query": query,
                "limit": 10,
            },
            headers=_headers(),
            service_name="HubSpot",
        )

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

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

        lines = [f"**Search: '{query}'** ({total} {obj_type}):", ""]

        for i, r in enumerate(results, 1):
            props = r.get("properties", {})
            rid = r.get("id", "")

            if obj_type == "contacts":
                name = f"{props.get('firstname', '')} {props.get('lastname', '')}".strip()
                email = props.get("email", "")
                lines.append(f"{i}. **{name or 'Unnamed'}** — {email} (ID: {rid})")
            else:
                name = props.get("dealname", "Unnamed")
                amount = props.get("amount", "")
                amt_str = f" — ${float(amount):,.2f}" if amount else ""
                lines.append(f"{i}. **{name}**{amt_str} (ID: {rid})")
            lines.append("")

        return "\n".join(lines)

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


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

TOOLS = [
    {
        "name": "hubspot_contacts",
        "description": "List HubSpot CRM contacts with name, email, company, and phone.",
        "input_schema": {
            "type": "object",
            "properties": {
                "limit": {
                    "type": "integer",
                    "description": "Max results (1-100, default 20)",
                    "default": 20,
                },
            },
        },
        "handler": hubspot_contacts,
        "category": "hubspot",
    },
    {
        "name": "hubspot_deals",
        "description": "List HubSpot CRM deals with stage, amount, and close date.",
        "input_schema": {
            "type": "object",
            "properties": {
                "limit": {
                    "type": "integer",
                    "description": "Max results (1-100, default 20)",
                    "default": 20,
                },
            },
        },
        "handler": hubspot_deals,
        "category": "hubspot",
    },
    {
        "name": "hubspot_add_contact",
        "description": "Create a new contact in HubSpot CRM.",
        "input_schema": {
            "type": "object",
            "properties": {
                "email": {"type": "string", "description": "Email address"},
                "firstname": {"type": "string", "description": "First name"},
                "lastname": {"type": "string", "description": "Last name"},
                "company": {"type": "string", "description": "Company name"},
                "phone": {"type": "string", "description": "Phone number"},
            },
            "required": ["email"],
        },
        "handler": hubspot_add_contact,
        "category": "hubspot",
    },
    {
        "name": "hubspot_search",
        "description": "Search HubSpot CRM contacts or deals by keyword.",
        "input_schema": {
            "type": "object",
            "properties": {
                "query": {"type": "string", "description": "Search query"},
                "object_type": {
                    "type": "string",
                    "description": "Object type: contacts, deals",
                    "default": "contacts",
                },
            },
            "required": ["query"],
        },
        "handler": hubspot_search,
        "category": "hubspot",
    },
]
