import { ServiceBubble } from '../../../types/service-bubble-class.js';
import { CredentialType } from '@bubblelab/shared-schemas';
import { StripeParamsSchema, StripeResultSchema, } from './stripe.schema.js';
/**
 * Stripe Service Bubble
 *
 * Comprehensive Stripe integration for payment and billing management.
 * Based on the Stripe MCP (Model Context Protocol) implementation.
 *
 * Features:
 * - Customer management (create, list)
 * - Product and price management
 * - Payment links creation
 * - Invoice management
 * - Subscription management
 * - Payment intents listing
 * - Refund creation
 * - Balance retrieval
 *
 * Use cases:
 * - Accept payments through payment links
 * - Manage customer billing and subscriptions
 * - Create and manage products and pricing
 * - Process refunds
 * - Monitor account balance
 *
 * Security Features:
 * - OAuth 2.0 authentication with Stripe
 * - Secure API key handling
 * - Input validation with Zod schemas
 */
export class StripeBubble extends ServiceBubble {
    static type = 'service';
    static service = 'stripe';
    static authType = 'apikey';
    static bubbleName = 'stripe';
    static schema = StripeParamsSchema;
    static resultSchema = StripeResultSchema;
    static shortDescription = 'Stripe integration for payments, billing, and subscriptions';
    static longDescription = `
    Stripe service integration for comprehensive payment and billing management.
    Based on the official Stripe MCP implementation.

    Features:
    - Customer management (create, list)
    - Product and price management
    - Payment links creation
    - Invoice management
    - Subscription management
    - Payment intents listing
    - Refund creation
    - Balance retrieval

    Use cases:
    - Accept payments through payment links
    - Manage customer billing and subscriptions
    - Create and manage products and pricing
    - Process refunds
    - Monitor account balance

    Security Features:
    - OAuth 2.0 authentication with Stripe
    - Secure API key handling
    - Input validation with Zod schemas
  `;
    static alias = 'payments';
    constructor(params = {
        operation: 'list_customers',
        limit: 10,
    }, context) {
        super(params, context);
    }
    async testCredential() {
        const credential = this.chooseCredential();
        if (!credential) {
            return false;
        }
        // Test by fetching account balance (minimal API call)
        const response = await this.makeStripeRequest('/v1/balance', 'GET');
        if (response === null || typeof response !== 'object') {
            throw new Error('Stripe API returned an invalid response');
        }
        return true;
    }
    async makeStripeRequest(endpoint, method = 'GET', body) {
        const credential = this.chooseCredential();
        if (!credential) {
            throw new Error('Stripe credentials are required');
        }
        const url = `https://api.stripe.com${endpoint}`;
        const headers = {
            Authorization: `Bearer ${credential}`,
            'Content-Type': 'application/x-www-form-urlencoded',
        };
        const requestInit = {
            method,
            headers,
        };
        if (body && method !== 'GET') {
            // Stripe API uses form-urlencoded format
            requestInit.body = this.encodeFormData(body);
        }
        const response = await fetch(url, requestInit);
        if (!response.ok) {
            const errorData = await response.json().catch(() => ({}));
            const errorMessage = errorData?.error?.message ||
                `Stripe API error: ${response.status} ${response.statusText}`;
            throw new Error(errorMessage);
        }
        return await response.json();
    }
    encodeFormData(data, prefix = '') {
        const params = [];
        for (const [key, value] of Object.entries(data)) {
            if (value === undefined || value === null)
                continue;
            const fullKey = prefix ? `${prefix}[${key}]` : key;
            if (typeof value === 'object' && !Array.isArray(value)) {
                params.push(this.encodeFormData(value, fullKey));
            }
            else if (Array.isArray(value)) {
                value.forEach((item, index) => {
                    if (typeof item === 'object') {
                        params.push(this.encodeFormData(item, `${fullKey}[${index}]`));
                    }
                    else {
                        params.push(`${encodeURIComponent(`${fullKey}[${index}]`)}=${encodeURIComponent(String(item))}`);
                    }
                });
            }
            else {
                params.push(`${encodeURIComponent(fullKey)}=${encodeURIComponent(String(value))}`);
            }
        }
        return params.filter(Boolean).join('&');
    }
    async performAction(context) {
        void context;
        const { operation } = this.params;
        try {
            const result = await (async () => {
                const parsedParams = this.params;
                switch (operation) {
                    case 'create_customer':
                        return await this.createCustomer(parsedParams);
                    case 'list_customers':
                        return await this.listCustomers(parsedParams);
                    case 'retrieve_customer':
                        return await this.retrieveCustomer(parsedParams);
                    case 'create_product':
                        return await this.createProduct(parsedParams);
                    case 'list_products':
                        return await this.listProducts(parsedParams);
                    case 'create_price':
                        return await this.createPrice(parsedParams);
                    case 'list_prices':
                        return await this.listPrices(parsedParams);
                    case 'create_payment_link':
                        return await this.createPaymentLink(parsedParams);
                    case 'create_invoice':
                        return await this.createInvoice(parsedParams);
                    case 'list_invoices':
                        return await this.listInvoices(parsedParams);
                    case 'retrieve_invoice':
                        return await this.retrieveInvoice(parsedParams);
                    case 'finalize_invoice':
                        return await this.finalizeInvoice(parsedParams);
                    case 'create_invoice_item':
                        return await this.createInvoiceItem(parsedParams);
                    case 'send_invoice':
                        return await this.sendInvoice(parsedParams);
                    case 'get_balance':
                        return await this.getBalance();
                    case 'list_payment_intents':
                        return await this.listPaymentIntents(parsedParams);
                    case 'list_subscriptions':
                        return await this.listSubscriptions(parsedParams);
                    case 'cancel_subscription':
                        return await this.cancelSubscription(parsedParams);
                    case 'list_payment_links':
                        return await this.listPaymentLinks(parsedParams);
                    case 'create_subscription':
                        return await this.createSubscription(parsedParams);
                    default:
                        throw new Error(`Unsupported operation: ${operation}`);
                }
            })();
            return result;
        }
        catch (error) {
            return {
                operation,
                success: false,
                error: error instanceof Error ? error.message : 'Unknown error occurred',
            };
        }
    }
    // ============================================================================
    // CUSTOMER OPERATIONS
    // ============================================================================
    async createCustomer(params) {
        const { name, email, metadata } = params;
        const body = { name };
        if (email)
            body.email = email;
        if (metadata)
            body.metadata = metadata;
        const response = await this.makeStripeRequest('/v1/customers', 'POST', body);
        const customer = response;
        return {
            operation: 'create_customer',
            success: true,
            customer: {
                id: customer.id,
                name: customer.name,
                email: customer.email,
                created: customer.created,
                metadata: customer.metadata,
            },
            error: '',
        };
    }
    async listCustomers(params) {
        const { limit, email, cursor } = params;
        const queryParams = new URLSearchParams();
        if (limit)
            queryParams.set('limit', String(limit));
        if (email)
            queryParams.set('email', email);
        if (cursor)
            queryParams.set('starting_after', cursor);
        const endpoint = `/v1/customers${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
        const response = await this.makeStripeRequest(endpoint, 'GET');
        const data = response;
        const customers = data.data.map((c) => ({
            id: c.id,
            name: c.name,
            email: c.email,
            created: c.created,
            metadata: c.metadata,
        }));
        // Get the last customer's ID as the cursor for the next page
        const nextCursor = data.has_more && customers.length > 0
            ? customers[customers.length - 1].id
            : null;
        return {
            operation: 'list_customers',
            success: true,
            customers,
            has_more: data.has_more,
            next_cursor: nextCursor,
            error: '',
        };
    }
    async retrieveCustomer(params) {
        const { customer_id } = params;
        const response = await this.makeStripeRequest(`/v1/customers/${customer_id}`, 'GET');
        const customer = response;
        // Handle deleted customers
        if (customer.deleted) {
            return {
                operation: 'retrieve_customer',
                success: true,
                customer: {
                    id: customer.id,
                    name: null,
                    email: null,
                    created: 0,
                    metadata: undefined,
                },
                deleted: true,
                error: '',
            };
        }
        return {
            operation: 'retrieve_customer',
            success: true,
            customer: {
                id: customer.id,
                name: customer.name ?? null,
                email: customer.email ?? null,
                created: customer.created ?? 0,
                metadata: customer.metadata,
            },
            deleted: false,
            error: '',
        };
    }
    // ============================================================================
    // PRODUCT OPERATIONS
    // ============================================================================
    async createProduct(params) {
        const { name, description, metadata } = params;
        const body = { name };
        if (description)
            body.description = description;
        if (metadata)
            body.metadata = metadata;
        const response = await this.makeStripeRequest('/v1/products', 'POST', body);
        const product = response;
        return {
            operation: 'create_product',
            success: true,
            product: {
                id: product.id,
                name: product.name,
                description: product.description,
                active: product.active,
                created: product.created,
                metadata: product.metadata,
            },
            error: '',
        };
    }
    async listProducts(params) {
        const { limit, active } = params;
        const queryParams = new URLSearchParams();
        if (limit)
            queryParams.set('limit', String(limit));
        if (active !== undefined)
            queryParams.set('active', String(active));
        const endpoint = `/v1/products${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
        const response = await this.makeStripeRequest(endpoint, 'GET');
        const data = response;
        return {
            operation: 'list_products',
            success: true,
            products: data.data.map((p) => ({
                id: p.id,
                name: p.name,
                description: p.description,
                active: p.active,
                created: p.created,
                metadata: p.metadata,
            })),
            error: '',
        };
    }
    // ============================================================================
    // PRICE OPERATIONS
    // ============================================================================
    async createPrice(params) {
        const { product, unit_amount, currency, recurring, metadata } = params;
        const body = {
            product,
            unit_amount,
            currency,
        };
        if (recurring)
            body.recurring = recurring;
        if (metadata)
            body.metadata = metadata;
        const response = await this.makeStripeRequest('/v1/prices', 'POST', body);
        const price = response;
        return {
            operation: 'create_price',
            success: true,
            price: {
                id: price.id,
                product: price.product,
                unit_amount: price.unit_amount,
                currency: price.currency,
                type: price.type,
                active: price.active,
                created: price.created,
                metadata: price.metadata,
            },
            error: '',
        };
    }
    async listPrices(params) {
        const { limit, product, active } = params;
        const queryParams = new URLSearchParams();
        if (limit)
            queryParams.set('limit', String(limit));
        if (product)
            queryParams.set('product', product);
        if (active !== undefined)
            queryParams.set('active', String(active));
        const endpoint = `/v1/prices${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
        const response = await this.makeStripeRequest(endpoint, 'GET');
        const data = response;
        return {
            operation: 'list_prices',
            success: true,
            prices: data.data.map((p) => ({
                id: p.id,
                product: p.product,
                unit_amount: p.unit_amount,
                currency: p.currency,
                type: p.type,
                active: p.active,
                created: p.created,
                metadata: p.metadata,
            })),
            error: '',
        };
    }
    // ============================================================================
    // PAYMENT LINK OPERATIONS
    // ============================================================================
    async createPaymentLink(params) {
        const { price, quantity, redirect_url, metadata } = params;
        const body = {
            line_items: [{ price, quantity }],
        };
        if (redirect_url) {
            body.after_completion = {
                type: 'redirect',
                redirect: { url: redirect_url },
            };
        }
        if (metadata)
            body.metadata = metadata;
        const response = await this.makeStripeRequest('/v1/payment_links', 'POST', body);
        const paymentLink = response;
        return {
            operation: 'create_payment_link',
            success: true,
            payment_link: {
                id: paymentLink.id,
                url: paymentLink.url,
                active: paymentLink.active,
                created: paymentLink.created,
                metadata: paymentLink.metadata,
            },
            error: '',
        };
    }
    // ============================================================================
    // INVOICE OPERATIONS
    // ============================================================================
    async createInvoice(params) {
        const { customer, auto_advance, collection_method, days_until_due, items, metadata, } = params;
        const body = {
            customer,
            auto_advance,
            collection_method,
        };
        if (days_until_due)
            body.days_until_due = days_until_due;
        if (metadata)
            body.metadata = metadata;
        const response = await this.makeStripeRequest('/v1/invoices', 'POST', body);
        let invoice = response;
        // If items are provided, create invoice items for each
        if (items && items.length > 0) {
            for (const item of items) {
                const quantity = item.quantity ?? 1;
                // Calculate total amount (unit_amount * quantity) since Stripe's `amount` is the total
                const totalAmount = item.unit_amount * quantity;
                const itemBody = {
                    customer,
                    invoice: invoice.id,
                    amount: totalAmount,
                    currency: invoice.currency,
                };
                if (item.description)
                    itemBody.description = item.description;
                await this.makeStripeRequest('/v1/invoiceitems', 'POST', itemBody);
            }
            // Retrieve the updated invoice to get the correct total
            const updatedResponse = await this.makeStripeRequest(`/v1/invoices/${invoice.id}`, 'GET');
            invoice = updatedResponse;
        }
        return {
            operation: 'create_invoice',
            success: true,
            invoice: {
                id: invoice.id,
                customer: invoice.customer,
                status: invoice.status,
                total: invoice.total,
                currency: invoice.currency,
                created: invoice.created,
                due_date: invoice.due_date
                    ? new Date(invoice.due_date * 1000).toISOString()
                    : null,
                hosted_invoice_url: invoice.hosted_invoice_url,
                metadata: invoice.metadata,
            },
            error: '',
        };
    }
    async listInvoices(params) {
        const { limit, customer, status, cursor } = params;
        const queryParams = new URLSearchParams();
        if (limit)
            queryParams.set('limit', String(limit));
        if (customer)
            queryParams.set('customer', customer);
        if (status)
            queryParams.set('status', status);
        if (cursor)
            queryParams.set('starting_after', cursor);
        const endpoint = `/v1/invoices${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
        const response = await this.makeStripeRequest(endpoint, 'GET');
        const data = response;
        const invoices = data.data.map((i) => ({
            id: i.id,
            customer: i.customer,
            status: i.status,
            total: i.total,
            currency: i.currency,
            created: i.created,
            due_date: i.due_date ? new Date(i.due_date * 1000).toISOString() : null,
            hosted_invoice_url: i.hosted_invoice_url,
            invoice_pdf: i.invoice_pdf,
            metadata: i.metadata,
        }));
        const nextCursor = data.has_more && invoices.length > 0
            ? invoices[invoices.length - 1].id
            : null;
        return {
            operation: 'list_invoices',
            success: true,
            invoices,
            has_more: data.has_more,
            next_cursor: nextCursor,
            error: '',
        };
    }
    async retrieveInvoice(params) {
        const { invoice_id } = params;
        const response = await this.makeStripeRequest(`/v1/invoices/${invoice_id}`, 'GET');
        const invoice = response;
        return {
            operation: 'retrieve_invoice',
            success: true,
            invoice: {
                id: invoice.id,
                customer: invoice.customer,
                status: invoice.status,
                total: invoice.total,
                currency: invoice.currency,
                created: invoice.created,
                due_date: invoice.due_date
                    ? new Date(invoice.due_date * 1000).toISOString()
                    : null,
                hosted_invoice_url: invoice.hosted_invoice_url,
                invoice_pdf: invoice.invoice_pdf,
                metadata: invoice.metadata,
            },
            error: '',
        };
    }
    async finalizeInvoice(params) {
        const { invoice_id, auto_advance } = params;
        const body = {};
        if (auto_advance !== undefined) {
            body.auto_advance = String(auto_advance);
        }
        const response = await this.makeStripeRequest(`/v1/invoices/${invoice_id}/finalize`, 'POST', Object.keys(body).length > 0 ? body : undefined);
        const invoice = response;
        return {
            operation: 'finalize_invoice',
            success: true,
            invoice: {
                id: invoice.id,
                customer: invoice.customer,
                status: invoice.status,
                total: invoice.total,
                currency: invoice.currency,
                created: invoice.created,
                due_date: invoice.due_date
                    ? new Date(invoice.due_date * 1000).toISOString()
                    : null,
                hosted_invoice_url: invoice.hosted_invoice_url,
                invoice_pdf: invoice.invoice_pdf,
                metadata: invoice.metadata,
            },
            error: '',
        };
    }
    async createInvoiceItem(params) {
        const { customer, invoice, unit_amount, currency, description, quantity, metadata, } = params;
        const qty = quantity ?? 1;
        // Calculate total amount (unit_amount * quantity) since Stripe's `amount` is the total
        const totalAmount = unit_amount * qty;
        const body = {
            customer,
            amount: totalAmount,
            currency,
        };
        if (invoice)
            body.invoice = invoice;
        if (description)
            body.description = description;
        if (metadata)
            body.metadata = metadata;
        const response = await this.makeStripeRequest('/v1/invoiceitems', 'POST', body);
        const invoiceItem = response;
        return {
            operation: 'create_invoice_item',
            success: true,
            invoice_item: {
                id: invoiceItem.id,
                invoice: invoiceItem.invoice,
                customer: invoiceItem.customer,
                amount: invoiceItem.amount,
                unit_amount: invoiceItem.unit_amount,
                currency: invoiceItem.currency,
                description: invoiceItem.description,
                quantity: invoiceItem.quantity,
                date: invoiceItem.date,
                metadata: invoiceItem.metadata,
            },
            error: '',
        };
    }
    async sendInvoice(params) {
        const { invoice_id } = params;
        // Use Stripe's send endpoint to send the invoice via Stripe's email service
        const response = await this.makeStripeRequest(`/v1/invoices/${invoice_id}/send`, 'POST');
        const invoice = response;
        return {
            operation: 'send_invoice',
            success: true,
            invoice: {
                id: invoice.id,
                customer: invoice.customer,
                status: invoice.status,
                total: invoice.total,
                currency: invoice.currency,
                created: invoice.created,
                due_date: invoice.due_date
                    ? new Date(invoice.due_date * 1000).toISOString()
                    : null,
                hosted_invoice_url: invoice.hosted_invoice_url,
                invoice_pdf: invoice.invoice_pdf,
                metadata: invoice.metadata,
            },
            error: '',
        };
    }
    // ============================================================================
    // BALANCE OPERATIONS
    // ============================================================================
    async getBalance() {
        const response = await this.makeStripeRequest('/v1/balance', 'GET');
        const balance = response;
        return {
            operation: 'get_balance',
            success: true,
            balance: {
                available: balance.available.map((b) => ({
                    amount: b.amount,
                    currency: b.currency,
                })),
                pending: balance.pending.map((b) => ({
                    amount: b.amount,
                    currency: b.currency,
                })),
            },
            error: '',
        };
    }
    // ============================================================================
    // PAYMENT INTENT OPERATIONS
    // ============================================================================
    async listPaymentIntents(params) {
        const { limit, customer } = params;
        const queryParams = new URLSearchParams();
        if (limit)
            queryParams.set('limit', String(limit));
        if (customer)
            queryParams.set('customer', customer);
        const endpoint = `/v1/payment_intents${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
        const response = await this.makeStripeRequest(endpoint, 'GET');
        const data = response;
        return {
            operation: 'list_payment_intents',
            success: true,
            payment_intents: data.data.map((pi) => ({
                id: pi.id,
                amount: pi.amount,
                currency: pi.currency,
                status: pi.status,
                customer: pi.customer,
                created: pi.created,
                metadata: pi.metadata,
            })),
            error: '',
        };
    }
    // ============================================================================
    // SUBSCRIPTION OPERATIONS
    // ============================================================================
    async listSubscriptions(params) {
        const { limit, customer, status } = params;
        const queryParams = new URLSearchParams();
        if (limit)
            queryParams.set('limit', String(limit));
        if (customer)
            queryParams.set('customer', customer);
        if (status && status !== 'all')
            queryParams.set('status', status);
        const endpoint = `/v1/subscriptions${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
        const response = await this.makeStripeRequest(endpoint, 'GET');
        const data = response;
        return {
            operation: 'list_subscriptions',
            success: true,
            subscriptions: data.data.map((s) => ({
                id: s.id,
                customer: s.customer,
                status: s.status,
                current_period_start: s.current_period_start,
                current_period_end: s.current_period_end,
                cancel_at_period_end: s.cancel_at_period_end,
                created: s.created,
                metadata: s.metadata,
            })),
            error: '',
        };
    }
    async cancelSubscription(params) {
        const { subscription_id, cancel_at_period_end } = params;
        let response;
        if (cancel_at_period_end) {
            // Update to cancel at period end
            response = await this.makeStripeRequest(`/v1/subscriptions/${subscription_id}`, 'POST', { cancel_at_period_end: true });
        }
        else {
            // Cancel immediately
            response = await this.makeStripeRequest(`/v1/subscriptions/${subscription_id}`, 'DELETE');
        }
        const subscription = response;
        return {
            operation: 'cancel_subscription',
            success: true,
            subscription: {
                id: subscription.id,
                customer: subscription.customer,
                status: subscription.status,
                current_period_start: subscription.current_period_start,
                current_period_end: subscription.current_period_end,
                cancel_at_period_end: subscription.cancel_at_period_end,
                created: subscription.created,
                metadata: subscription.metadata,
            },
            error: '',
        };
    }
    // ============================================================================
    // PAYMENT LINK LIST OPERATIONS
    // ============================================================================
    async listPaymentLinks(params) {
        const { limit, active } = params;
        const queryParams = new URLSearchParams();
        if (limit)
            queryParams.set('limit', String(limit));
        if (active !== undefined)
            queryParams.set('active', String(active));
        const endpoint = `/v1/payment_links${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
        const response = await this.makeStripeRequest(endpoint, 'GET');
        const data = response;
        return {
            operation: 'list_payment_links',
            success: true,
            payment_links: data.data.map((pl) => ({
                id: pl.id,
                url: pl.url,
                active: pl.active,
                created: pl.created,
                metadata: pl.metadata,
            })),
            error: '',
        };
    }
    // ============================================================================
    // SUBSCRIPTION CREATE OPERATIONS
    // ============================================================================
    async createSubscription(params) {
        const { customer, price, trial_period_days, payment_behavior, metadata } = params;
        const body = {
            customer,
            items: [{ price }],
            payment_behavior: payment_behavior || 'default_incomplete',
        };
        if (trial_period_days)
            body.trial_period_days = trial_period_days;
        if (metadata)
            body.metadata = metadata;
        const response = await this.makeStripeRequest('/v1/subscriptions', 'POST', body);
        const subscription = response;
        return {
            operation: 'create_subscription',
            success: true,
            subscription: {
                id: subscription.id,
                customer: subscription.customer,
                status: subscription.status,
                current_period_start: subscription.current_period_start,
                current_period_end: subscription.current_period_end,
                cancel_at_period_end: subscription.cancel_at_period_end,
                created: subscription.created,
                metadata: subscription.metadata,
            },
            error: '',
        };
    }
    // ============================================================================
    // CREDENTIAL MANAGEMENT
    // ============================================================================
    chooseCredential() {
        const { credentials } = this.params;
        if (!credentials || typeof credentials !== 'object') {
            return undefined;
        }
        // Stripe bubble uses STRIPE_CRED credentials
        return credentials[CredentialType.STRIPE_CRED];
    }
}
//# sourceMappingURL=stripe.js.map