<cfscript>
/**
 * Stripe Webhook Handler
 * Handles payment confirmations, refunds, and disputes
 *
 * Webhook events to configure in Stripe:
 * - payment_intent.succeeded
 * - payment_intent.payment_failed
 * - charge.refunded
 * - charge.dispute.created
 */

response = { "OK": false };

try {
    // Get raw request body
    payload = toString(getHttpRequestData().content);

    // Get Stripe signature header
    sigHeader = getHttpRequestData().headers["Stripe-Signature"] ?: "";

    // Webhook secret (set in Stripe dashboard)
    webhookSecret = application.stripeWebhookSecret ?: "";

    // For now, skip signature verification in development
    // In production, uncomment and implement signature verification:
    /*
    if (webhookSecret != "" && sigHeader != "") {
        // Verify webhook signature
        // This requires computing HMAC-SHA256 and comparing
        // See: https://stripe.com/docs/webhooks/signatures
    }
    */

    // Parse event
    event = deserializeJSON(payload);
    eventType = event.type ?: "";
    eventData = event.data.object ?: {};

    // Log the webhook
    writeLog(file="stripe_webhooks", text="Received: #eventType# - #eventData.id ?: 'unknown'#");

    switch (eventType) {

        case "payment_intent.succeeded":
            // Payment was successful
            paymentIntentID = eventData.id;
            orderID = val(eventData.metadata.order_id ?: 0);

            if (orderID > 0) {
                // Update order status to paid/submitted
                queryExecute("
                    UPDATE Orders
                    SET OrderPaymentStatus = 'paid',
                        OrderPaymentCompletedOn = NOW(),
                        OrderStatusID = CASE WHEN OrderStatusID = 0 THEN 1 ELSE OrderStatusID END
                    WHERE OrderID = :orderID
                ", { orderID: orderID });

                // Create a task for the new order
                queryExecute("
                    INSERT INTO Tasks (TaskBusinessID, TaskCategoryID, TaskTitle, TaskCreatedOn, TaskStatusID, TaskSourceType, TaskSourceID)
                    SELECT o.OrderBusinessID, 1, CONCAT('Order #', o.OrderID), NOW(), 0, 'order', o.OrderID
                    FROM Orders o
                    WHERE o.OrderID = :orderID
                    AND NOT EXISTS (SELECT 1 FROM Tasks t WHERE t.TaskSourceType = 'order' AND t.TaskSourceID = :orderID)
                ", { orderID: orderID });

                writeLog(file="stripe_webhooks", text="Order #orderID# marked as paid");
            }
            break;

        case "payment_intent.payment_failed":
            // Payment failed
            paymentIntentID = eventData.id;
            orderID = val(eventData.metadata.order_id ?: 0);
            failureMessage = eventData.last_payment_error.message ?: "Payment failed";

            if (orderID > 0) {
                queryExecute("
                    UPDATE Orders
                    SET OrderPaymentStatus = 'failed',
                        OrderPaymentError = :failureMessage
                    WHERE OrderID = :orderID
                ", {
                    orderID: orderID,
                    failureMessage: failureMessage
                });

                writeLog(file="stripe_webhooks", text="Order #orderID# payment failed: #failureMessage#");
            }
            break;

        case "charge.refunded":
            // Handle refund
            chargeID = eventData.id;
            paymentIntentID = eventData.payment_intent ?: "";
            refundAmount = eventData.amount_refunded / 100;

            if (paymentIntentID != "") {
                qOrder = queryExecute("
                    SELECT OrderID FROM Orders
                    WHERE OrderStripePaymentIntentID = :paymentIntentID
                ", { paymentIntentID: paymentIntentID });

                if (qOrder.recordCount > 0) {
                    queryExecute("
                        UPDATE Orders
                        SET OrderPaymentStatus = 'refunded',
                            OrderRefundAmount = :refundAmount,
                            OrderRefundedOn = NOW()
                        WHERE OrderStripePaymentIntentID = :paymentIntentID
                    ", {
                        paymentIntentID: paymentIntentID,
                        refundAmount: refundAmount
                    });

                    writeLog(file="stripe_webhooks", text="Order refunded: $#refundAmount#");
                }
            }
            break;

        case "charge.dispute.created":
            // Customer disputed a charge
            chargeID = eventData.id;
            paymentIntentID = eventData.payment_intent ?: "";

            if (paymentIntentID != "") {
                qOrder = queryExecute("
                    SELECT OrderID, OrderBusinessID FROM Orders
                    WHERE OrderStripePaymentIntentID = :paymentIntentID
                ", { paymentIntentID: paymentIntentID });

                if (qOrder.recordCount > 0) {
                    queryExecute("
                        UPDATE Orders
                        SET OrderPaymentStatus = 'disputed'
                        WHERE OrderStripePaymentIntentID = :paymentIntentID
                    ", { paymentIntentID: paymentIntentID });

                    // Create a task for the dispute
                    queryExecute("
                        INSERT INTO Tasks (TaskBusinessID, TaskCategoryID, TaskTitle, TaskDetails, TaskCreatedOn, TaskStatusID, TaskSourceType, TaskSourceID)
                        VALUES (:businessID, 4, 'Payment Dispute', 'Order ###qOrder.OrderID# has been disputed. Review immediately.', NOW(), 0, 'dispute', :orderID)
                    ", {
                        businessID: qOrder.OrderBusinessID,
                        orderID: qOrder.OrderID
                    });

                    writeLog(file="stripe_webhooks", text="Dispute created for order #qOrder.OrderID#");
                }
            }
            break;

        case "account.updated":
            // Connected account was updated
            accountID = eventData.id;
            chargesEnabled = eventData.charges_enabled ?: false;
            payoutsEnabled = eventData.payouts_enabled ?: false;

            if (chargesEnabled && payoutsEnabled) {
                queryExecute("
                    UPDATE Businesses
                    SET BusinessStripeOnboardingComplete = 1
                    WHERE BusinessStripeAccountID = :accountID
                ", { accountID: accountID });

                writeLog(file="stripe_webhooks", text="Account #accountID# is now fully active");
            }
            break;

        default:
            writeLog(file="stripe_webhooks", text="Unhandled event type: #eventType#");
    }

    response["OK"] = true;
    response["RECEIVED"] = true;

} catch (any e) {
    writeLog(file="stripe_webhooks", text="Error: #e.message#");
    response["ERROR"] = e.message;
}

writeOutput(serializeJSON(response));
</cfscript>
