# 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

"""
Square Payment & Commerce Skill

List payments, manage customers, create invoices, browse catalog.
Works for Chef (restaurant POS), Artist (show sales), Business Buddy (commerce).

Setup:
    SQUARE_ACCESS_TOKEN=your_access_token
    SQUARE_LOCATION_ID=your_location_id  (from Square Dashboard > Locations)

Get credentials at: https://developer.squareup.com/apps

API: https://connect.squareup.com/v2/
"""

import logging

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

logger = logging.getLogger(__name__)

BASE_URL = "https://connect.squareup.com/v2"
API_VERSION = "2025-10-16"


def _access_token() -> str:
    return get_env("SQUARE_ACCESS_TOKEN") or ""


def _location_id() -> str:
    return get_env("SQUARE_LOCATION_ID") or ""


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


def _check_config() -> str:
    if not _access_token():
        return (
            "Square not configured.\n"
            "Set SQUARE_ACCESS_TOKEN in your environment.\n"
            "Get credentials at: https://developer.squareup.com/apps"
        )
    return ""


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


def square_payments(data: dict) -> str:
    """List recent Square payments."""
    err = _check_config()
    if err:
        return err

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

    try:
        params = {"limit": limit, "sort_order": "DESC"}
        location = _location_id()
        if location:
            params["location_id"] = location

        result = _payments_cached(limit, location)

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

        lines = [f"**Recent Payments** (showing {len(payments)}):", ""]

        for i, p in enumerate(payments, 1):
            payment_id = p.get("id", "")
            amount_money = p.get("amount_money", {})
            amount = amount_money.get("amount", 0) / 100
            currency = amount_money.get("currency", "USD")
            status = p.get("status", "unknown")
            source_type = p.get("source_type", "")
            created = p.get("created_at", "")[:16]
            receipt_url = p.get("receipt_url", "")

            lines.append(f"{i}. **${amount:.2f} {currency}** — {status}")
            details = [f"ID: {payment_id[:20]}..."]
            if source_type:
                details.append(source_type)
            if created:
                details.append(created)
            lines.append(f"   {' | '.join(details)}")
            if receipt_url:
                lines.append(f"   Receipt: {receipt_url}")
            lines.append("")

        return "\n".join(lines)

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


@cached(prefix="square_payments", ttl=60)
def _payments_cached(limit: int, location: str) -> dict:
    params = {"limit": limit, "sort_order": "DESC"}
    if location:
        params["location_id"] = location
    return api_get(
        f"{BASE_URL}/payments",
        params=params,
        headers=_headers(),
        service_name="Square",
    )


def square_customers(data: dict) -> str:
    """List or search Square customers."""
    err = _check_config()
    if err:
        return err

    limit = min(int(data.get("limit", 20)), 100)
    sort_field = data.get("sort_field", "CREATED_AT")
    sort_order = data.get("sort_order", "DESC")

    try:
        result = _customers_cached(limit, sort_field, sort_order)

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

        lines = [f"**Customers** (showing {len(customers)}):", ""]

        for i, c in enumerate(customers, 1):
            cust_id = c.get("id", "")
            given_name = c.get("given_name", "")
            family_name = c.get("family_name", "")
            name = f"{given_name} {family_name}".strip() or "Unnamed"
            email = c.get("email_address", "")
            phone = c.get("phone_number", "")
            created = c.get("created_at", "")[:10]

            lines.append(f"{i}. **{name}** (ID: {cust_id[:15]}...)")
            details = []
            if email:
                details.append(email)
            if phone:
                details.append(phone)
            if created:
                details.append(f"Since {created}")
            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("Square customers error: %s", e)
        return f"Error fetching customers: {e}"


@cached(prefix="square_customers", ttl=120)
def _customers_cached(limit: int, sort_field: str, sort_order: str) -> dict:
    return api_get(
        f"{BASE_URL}/customers",
        params={"limit": limit, "sort_field": sort_field, "sort_order": sort_order},
        headers=_headers(),
        service_name="Square",
    )


def square_invoices(data: dict) -> str:
    """List Square invoices."""
    err = _check_config()
    if err:
        return err

    location = _location_id()
    if not location:
        return "SQUARE_LOCATION_ID required for invoices."

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

    try:
        result = _invoices_cached(location, limit)

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

        lines = [f"**Invoices** (showing {len(invoices)}):", ""]

        for i, inv in enumerate(invoices, 1):
            inv_id = inv.get("id", "")
            status = inv.get("status", "unknown")
            title = inv.get("title", "")

            # Payment requests contain the amount info
            pay_requests = inv.get("payment_requests", [])
            total_str = ""
            if pay_requests:
                computed = pay_requests[0].get("computed_amount_money", {})
                if computed:
                    amt = computed.get("amount", 0) / 100
                    cur = computed.get("currency", "USD")
                    total_str = f"${amt:.2f} {cur}"

            created = inv.get("created_at", "")[:10]

            lines.append(f"{i}. **{title or 'Invoice'}** — {status}")
            details = [f"ID: {inv_id[:20]}"]
            if total_str:
                details.append(total_str)
            if created:
                details.append(created)
            lines.append(f"   {' | '.join(details)}")
            lines.append("")

        return "\n".join(lines)

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


@cached(prefix="square_invoices", ttl=120)
def _invoices_cached(location: str, limit: int) -> dict:
    return api_get(
        f"{BASE_URL}/invoices",
        params={"location_id": location, "limit": limit},
        headers=_headers(),
        service_name="Square",
    )


def square_catalog(data: dict) -> str:
    """Browse Square catalog items."""
    err = _check_config()
    if err:
        return err

    types = data.get("types", "ITEM")
    limit = min(int(data.get("limit", 20)), 200)

    try:
        result = _catalog_cached(types, limit)

        objects = result.get("objects", [])
        if not objects:
            return f"No catalog items of type '{types}' found."

        lines = [f"**Catalog Items** ({types}, showing {len(objects)}):", ""]

        for i, obj in enumerate(objects, 1):
            obj_id = obj.get("id", "")
            obj_type = obj.get("type", "")
            item_data = obj.get("item_data", {})
            name = item_data.get("name", obj_id)
            description = item_data.get("description", "")

            # Get price from first variation
            variations = item_data.get("variations", [])
            price_str = ""
            if variations:
                var_data = variations[0].get("item_variation_data", {})
                price_money = var_data.get("price_money", {})
                if price_money:
                    amt = price_money.get("amount", 0) / 100
                    cur = price_money.get("currency", "USD")
                    price_str = f"${amt:.2f} {cur}"

            lines.append(f"{i}. **{name}**")
            details = [f"Type: {obj_type}", f"ID: {obj_id[:15]}"]
            if price_str:
                details.append(price_str)
            lines.append(f"   {' | '.join(details)}")
            if description:
                lines.append(f"   {description[:100]}")
            lines.append("")

        return "\n".join(lines)

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


@cached(prefix="square_catalog", ttl=300)
def _catalog_cached(types: str, limit: int) -> dict:
    return api_get(
        f"{BASE_URL}/catalog/list",
        params={"types": types, "limit": limit},
        headers=_headers(),
        service_name="Square",
    )


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

TOOLS = [
    {
        "name": "square_payments",
        "description": (
            "List recent Square payments. Shows amount, status, source type, and receipt URLs."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "limit": {
                    "type": "integer",
                    "description": "Max results (1-100, default 10)",
                    "default": 10,
                },
            },
        },
        "handler": square_payments,
        "category": "square",
    },
    {
        "name": "square_customers",
        "description": ("List Square customers. Shows name, email, phone, and creation date."),
        "input_schema": {
            "type": "object",
            "properties": {
                "limit": {
                    "type": "integer",
                    "description": "Max results (1-100, default 20)",
                    "default": 20,
                },
                "sort_field": {
                    "type": "string",
                    "description": "Sort by: CREATED_AT, DEFAULT",
                    "default": "CREATED_AT",
                },
                "sort_order": {
                    "type": "string",
                    "description": "Sort order: ASC, DESC",
                    "default": "DESC",
                },
            },
        },
        "handler": square_customers,
        "category": "square",
    },
    {
        "name": "square_invoices",
        "description": (
            "List Square invoices."
            " Shows status, amount, and creation date. Requires SQUARE_LOCATION_ID."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "limit": {
                    "type": "integer",
                    "description": "Max results (1-100, default 20)",
                    "default": 20,
                },
            },
        },
        "handler": square_invoices,
        "category": "square",
    },
    {
        "name": "square_catalog",
        "description": (
            "Browse Square catalog items, categories, and variations."
            " Shows names, prices, and descriptions."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "types": {
                    "type": "string",
                    "description": "Catalog type: ITEM, CATEGORY, DISCOUNT, TAX",
                    "default": "ITEM",
                },
                "limit": {
                    "type": "integer",
                    "description": "Max results (1-200, default 20)",
                    "default": 20,
                },
            },
        },
        "handler": square_catalog,
        "category": "square",
    },
]
