# 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

"""
Stripe Payment Skill

Create payment links, list payments, create invoices, process refunds.
Works for Chef (restaurant POS), Artist (show sales), Nonprofit (donations).

Setup:
    STRIPE_SECRET_KEY=sk_live_... (or sk_test_... for testing)

Get credentials at: https://dashboard.stripe.com/apikeys

API: https://api.stripe.com/v1/
"""

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.stripe.com/v1"


def _secret_key() -> str:
    return get_env("STRIPE_SECRET_KEY") or ""


def _headers() -> dict:
    return {"Authorization": f"Bearer {_secret_key()}"}


def _check_config() -> str:
    if not _secret_key():
        return (
            "Stripe not configured.\n"
            "Set STRIPE_SECRET_KEY in your environment.\n"
            "Get your key at: https://dashboard.stripe.com/apikeys"
        )
    return ""


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


def create_payment_link(data: dict) -> str:
    """Create a Stripe payment link."""
    err = _check_config()
    if err:
        return err

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

    amount = data.get("amount", 0)
    if not amount or float(amount) <= 0:
        return "Please provide a valid amount."

    currency = data.get("currency", "usd").lower()

    try:
        # Stripe uses form-encoded data and amounts in cents
        amount_cents = int(float(amount) * 100)

        result = api_post(
            f"{BASE_URL}/payment_links",
            data={
                "line_items[0][price_data][currency]": currency,
                "line_items[0][price_data][product_data][name]": name,
                "line_items[0][price_data][unit_amount]": str(amount_cents),
                "line_items[0][quantity]": "1",
            },
            headers=_headers(),
            service_name="Stripe",
        )

        link_id = result.get("id", "")
        url = result.get("url", "")
        active = result.get("active", True)

        lines = [
            "**Payment Link Created!**",
            "",
            f"  ID: {link_id}",
            f"  URL: {url}",
            f"  Amount: ${float(amount):.2f} {currency.upper()}",
            f"  Status: {'Active' if active else 'Inactive'}",
            "",
            "Share this link to accept payments.",
        ]
        return "\n".join(lines)

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("Stripe payment link error: %s", e)
        return f"Error creating payment link: {e}"


def list_payments(data: dict) -> str:
    """List recent payments/charges."""
    err = _check_config()
    if err:
        return err

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

    try:
        result = _payments_cached(limit)

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

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

        for i, charge in enumerate(charges, 1):
            charge_id = charge.get("id", "")
            amount = charge.get("amount", 0) / 100
            currency = charge.get("currency", "usd").upper()
            status = charge.get("status", "unknown")
            description = charge.get("description", "")
            customer = charge.get("customer", "")

            lines.append(f"{i}. **${amount:.2f} {currency}** — {status}")
            details = [f"ID: {charge_id}"]
            if description:
                details.append(description)
            if customer:
                details.append(f"Customer: {customer}")
            lines.append(f"   {' | '.join(details)}")
            lines.append("")

        has_more = result.get("has_more", False)
        if has_more:
            lines.append("More payments available. Increase limit to see more.")

        return "\n".join(lines)

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


@cached(prefix="stripe_payments", ttl=60)
def _payments_cached(limit: int) -> dict:
    return api_get(
        f"{BASE_URL}/charges",
        params={"limit": limit},
        headers=_headers(),
        service_name="Stripe",
    )


def create_invoice(data: dict) -> str:
    """Create and optionally send a Stripe invoice."""
    err = _check_config()
    if err:
        return err

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

    description = data.get("description", "").strip()
    amount = data.get("amount", 0)
    if not amount or float(amount) <= 0:
        return "Please provide a valid amount."

    currency = data.get("currency", "usd").lower()
    auto_send = data.get("auto_send", False)

    try:
        # First, find or create customer by email
        customer_result = api_get(
            f"{BASE_URL}/customers",
            params={"email": customer_email, "limit": 1},
            headers=_headers(),
            service_name="Stripe",
        )

        customers = customer_result.get("data", [])
        if customers:
            customer_id = customers[0].get("id", "")
        else:
            # Create customer
            new_customer = api_post(
                f"{BASE_URL}/customers",
                data={"email": customer_email},
                headers=_headers(),
                service_name="Stripe",
            )
            customer_id = new_customer.get("id", "")

        # Create invoice
        invoice_data = {
            "customer": customer_id,
            "collection_method": "send_invoice",
            "days_until_due": "30",
        }
        if description:
            invoice_data["description"] = description

        invoice = api_post(
            f"{BASE_URL}/invoices",
            data=invoice_data,
            headers=_headers(),
            service_name="Stripe",
        )

        invoice_id = invoice.get("id", "")

        # Add line item
        amount_cents = int(float(amount) * 100)
        api_post(
            f"{BASE_URL}/invoiceitems",
            data={
                "customer": customer_id,
                "invoice": invoice_id,
                "amount": str(amount_cents),
                "currency": currency,
                "description": description or "Invoice item",
            },
            headers=_headers(),
            service_name="Stripe",
        )

        # Finalize the invoice
        finalized = api_post(
            f"{BASE_URL}/invoices/{invoice_id}/finalize",
            data={},
            headers=_headers(),
            service_name="Stripe",
        )

        status = finalized.get("status", "draft")
        hosted_url = finalized.get("hosted_invoice_url", "")

        # Send if requested
        if auto_send:
            api_post(
                f"{BASE_URL}/invoices/{invoice_id}/send",
                data={},
                headers=_headers(),
                service_name="Stripe",
            )
            status = "sent"

        lines = [
            "**Invoice Created!**",
            "",
            f"  Invoice ID: {invoice_id}",
            f"  Customer: {customer_email}",
            f"  Amount: ${float(amount):.2f} {currency.upper()}",
            f"  Status: {status}",
        ]
        if hosted_url:
            lines.append(f"  Payment URL: {hosted_url}")
        if not auto_send:
            lines.append("\nUse Stripe dashboard to send, or set auto_send=true.")

        return "\n".join(lines)

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("Stripe create invoice error: %s", e)
        return f"Error creating invoice: {e}"


def donation_link(data: dict) -> str:
    """Create a payment link configured for donations."""
    err = _check_config()
    if err:
        return err

    org_name = data.get("org_name", "").strip()
    if not org_name:
        return "Please provide the organization name (org_name)."

    suggested_amount = data.get("suggested_amount", 0)
    currency = data.get("currency", "usd").lower()

    try:
        link_data = {
            "line_items[0][price_data][currency]": currency,
            "line_items[0][price_data][product_data][name]": f"Donation to {org_name}",
            "line_items[0][quantity]": "1",
        }

        if suggested_amount and float(suggested_amount) > 0:
            amount_cents = int(float(suggested_amount) * 100)
            link_data["line_items[0][price_data][unit_amount]"] = str(amount_cents)
        else:
            # Custom amount — use price with custom unit amount
            link_data["line_items[0][price_data][unit_amount]"] = "100"
            link_data["line_items[0][adjustable_quantity[enabled]]"] = "true"
            link_data["line_items[0][adjustable_quantity[minimum]]"] = "1"
            link_data["line_items[0][adjustable_quantity[maximum]]"] = "10000"

        result = api_post(
            f"{BASE_URL}/payment_links",
            data=link_data,
            headers=_headers(),
            service_name="Stripe",
        )

        link_id = result.get("id", "")
        url = result.get("url", "")

        lines = [
            "**Donation Link Created!**",
            "",
            f"  Organization: {org_name}",
            f"  Link ID: {link_id}",
            f"  URL: {url}",
        ]
        if suggested_amount and float(suggested_amount) > 0:
            lines.append(f"  Suggested Amount: ${float(suggested_amount):.2f} {currency.upper()}")
        lines.append("\nShare this link to accept donations.")

        return "\n".join(lines)

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("Stripe donation link error: %s", e)
        return f"Error creating donation link: {e}"


def refund_payment(data: dict) -> str:
    """Refund a payment/charge."""
    err = _check_config()
    if err:
        return err

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

    amount = data.get("amount")
    reason = data.get("reason", "requested_by_customer")

    try:
        refund_data = {"charge": charge_id, "reason": reason}
        if amount:
            amount_cents = int(float(amount) * 100)
            refund_data["amount"] = str(amount_cents)

        result = api_post(
            f"{BASE_URL}/refunds",
            data=refund_data,
            headers=_headers(),
            service_name="Stripe",
        )

        refund_id = result.get("id", "")
        refund_amount = result.get("amount", 0) / 100
        currency = result.get("currency", "usd").upper()
        status = result.get("status", "")

        lines = [
            "**Refund Processed!**",
            "",
            f"  Refund ID: {refund_id}",
            f"  Charge: {charge_id}",
            f"  Amount: ${refund_amount:.2f} {currency}",
            f"  Status: {status}",
        ]
        return "\n".join(lines)

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("Stripe refund error: %s", e)
        return f"Error processing refund: {e}"


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

TOOLS = [
    {
        "name": "create_payment_link",
        "description": (
            "Create a Stripe payment link for a product or service."
            " Share the link to accept payments instantly."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "name": {
                    "type": "string",
                    "description": "Product or service name",
                },
                "amount": {
                    "type": "number",
                    "description": "Amount in dollars (e.g., 25.00)",
                },
                "currency": {
                    "type": "string",
                    "description": "Currency code (default: usd)",
                    "default": "usd",
                },
            },
            "required": ["name", "amount"],
        },
        "handler": create_payment_link,
        "category": "stripe_pay",
    },
    {
        "name": "list_payments",
        "description": (
            "List recent Stripe payments/charges. Shows amount, status, customer, and description."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "limit": {
                    "type": "integer",
                    "description": "Max results (1-100, default 10)",
                    "default": 10,
                },
            },
        },
        "handler": list_payments,
        "category": "stripe_pay",
    },
    {
        "name": "create_invoice",
        "description": (
            "Create a Stripe invoice for a customer."
            " Finds or creates customer by email, adds line item, finalizes."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "customer_email": {
                    "type": "string",
                    "description": "Customer email address",
                },
                "amount": {
                    "type": "number",
                    "description": "Invoice amount in dollars",
                },
                "description": {
                    "type": "string",
                    "description": "Invoice description / line item",
                },
                "currency": {
                    "type": "string",
                    "description": "Currency code (default: usd)",
                    "default": "usd",
                },
                "auto_send": {
                    "type": "boolean",
                    "description": "Auto-send to customer (default: false)",
                    "default": False,
                },
            },
            "required": ["customer_email", "amount"],
        },
        "handler": create_invoice,
        "category": "stripe_pay",
    },
    {
        "name": "donation_link",
        "description": (
            "Create a payment link configured for nonprofit donations."
            " Supports suggested amounts or custom donor-chosen amounts."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "org_name": {
                    "type": "string",
                    "description": "Organization name shown to donors",
                },
                "suggested_amount": {
                    "type": "number",
                    "description": "Suggested donation amount (0 for custom amount)",
                    "default": 0,
                },
                "currency": {
                    "type": "string",
                    "description": "Currency code (default: usd)",
                    "default": "usd",
                },
            },
            "required": ["org_name"],
        },
        "handler": donation_link,
        "category": "stripe_pay",
    },
    {
        "name": "refund_payment",
        "description": (
            "Refund a Stripe payment/charge. Full or partial refund with reason tracking."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "charge_id": {
                    "type": "string",
                    "description": "Charge ID to refund (ch_...)",
                },
                "amount": {
                    "type": "number",
                    "description": "Partial refund amount in dollars (omit for full refund)",
                },
                "reason": {
                    "type": "string",
                    "description": "Reason: requested_by_customer, duplicate, fraudulent",
                    "default": "requested_by_customer",
                },
            },
            "required": ["charge_id"],
        },
        "handler": refund_payment,
        "category": "stripe_pay",
    },
]
