<cfsetting showdebugoutput="false">
<cfsetting enablecfoutputonly="true">
<cfcontent type="application/json; charset=utf-8" reset="true">

<cfscript>
/**
 * Create Payment Intent for Order (v2 - with Payfrit fee structure)
 *
 * Fee Structure:
 *   - Customer pays: Subtotal + tax + tip + 5% Payfrit fee + card processing (2.9% + $0.30)
 *   - Restaurant receives: Subtotal - 5% Payfrit fee + tax + tip
 *   - Payfrit receives: 10% of subtotal (5% from customer + 5% from restaurant)
 *
 * POST: {
 *   BusinessID: int,
 *   OrderID: int,
 *   Subtotal: number (order subtotal in dollars, before fees),
 *   Tax: number (tax amount in dollars),
 *   Tip: number (optional, in dollars),
 *   CustomerEmail: string (optional)
 * }
 */

response = { "OK": false };

try {
    requestData = deserializeJSON(toString(getHttpRequestData().content));

    businessID = val(requestData.BusinessID ?: 0);
    orderID = val(requestData.OrderID ?: 0);
    subtotal = val(requestData.Subtotal ?: 0);
    tax = val(requestData.Tax ?: 0);
    tip = val(requestData.Tip ?: 0);
    customerEmail = requestData.CustomerEmail ?: "";

    if (businessID == 0) {
        response["ERROR"] = "BusinessID is required";
        writeOutput(serializeJSON(response));
        abort;
    }

    if (orderID == 0) {
        response["ERROR"] = "OrderID is required";
        writeOutput(serializeJSON(response));
        abort;
    }

    if (subtotal <= 0) {
        response["ERROR"] = "Invalid subtotal";
        writeOutput(serializeJSON(response));
        abort;
    }

    // Use test keys
    stripeSecretKey = application.stripeSecretKey ?: "sk_test_LfbmDduJxTwbVZmvcByYmirw";

    if (stripeSecretKey == "") {
        response["ERROR"] = "Stripe is not configured";
        writeOutput(serializeJSON(response));
        abort;
    }

    // Get business Stripe account and fee settings
    qBusiness = queryExecute("
        SELECT StripeAccountID, StripeOnboardingComplete, Name, PayfritFee
        FROM Businesses
        WHERE ID = :businessID
    ", { businessID: businessID }, { datasource: "payfrit" });

    if (qBusiness.recordCount == 0) {
        response["ERROR"] = "Business not found";
        writeOutput(serializeJSON(response));
        abort;
    }

    // Get order's delivery fee and grant economics (if applicable)
    qOrder = queryExecute("
        SELECT DeliveryFee, OrderTypeID, GrantID, GrantOwnerBusinessID, GrantEconomicsType, GrantEconomicsValue
        FROM Orders
        WHERE ID = :orderID
    ", { orderID: orderID }, { datasource: "payfrit" });

    deliveryFee = 0;
    if (qOrder.recordCount > 0 && qOrder.OrderTypeID == 3) {
        deliveryFee = val(qOrder.DeliveryFee);
    }

    // SP-SM: Resolve grant economics
    grantOwnerFeeCents = 0;
    grantOwnerBusinessID = 0;
    grantID = 0;
    if (qOrder.recordCount > 0 && val(qOrder.GrantID) > 0) {
        grantID = val(qOrder.GrantID);
        grantOwnerBusinessID = val(qOrder.GrantOwnerBusinessID);
        grantEconType = qOrder.GrantEconomicsType ?: "none";
        grantEconValue = val(qOrder.GrantEconomicsValue);

        if (grantEconType == "flat_fee" && grantEconValue > 0) {
            grantOwnerFeeCents = round(grantEconValue * 100);
        } else if (grantEconType == "percent_of_orders" && grantEconValue > 0) {
            grantOwnerFeeCents = round(subtotal * (grantEconValue / 100) * 100);
        }
    }

    // For testing, allow orders even without Stripe Connect setup
    hasStripeConnect = qBusiness.StripeOnboardingComplete == 1 && len(trim(qBusiness.StripeAccountID)) > 0;

    // ============================================================
    // FEE CALCULATION
    // ============================================================
    // Customer fee from database (PayfritFee), default 5% if not set
    customerFeePercent = isNumeric(qBusiness.PayfritFee) && qBusiness.PayfritFee > 0 ? qBusiness.PayfritFee : 0.05;
    businessFeePercent = 0.05;   // 5% business pays to Payfrit (always)
    cardFeePercent = 0.029;      // 2.9% Stripe fee
    cardFeeFixed = 0.30;         // $0.30 Stripe fixed fee

    payfritCustomerFee = subtotal * customerFeePercent;
    payfritBusinessFee = subtotal * businessFeePercent;
    totalBeforeCardFee = subtotal + tax + tip + deliveryFee + payfritCustomerFee;
    cardFee = (totalBeforeCardFee * cardFeePercent) + cardFeeFixed;
    totalCustomerPays = totalBeforeCardFee + cardFee;

    // Convert to cents for Stripe
    totalAmountCents = round(totalCustomerPays * 100);
    totalPlatformFeeCents = round((payfritCustomerFee + payfritBusinessFee) * 100);

    // Create PaymentIntent
    httpService = new http();
    httpService.setMethod("POST");
    httpService.setUrl("https://api.stripe.com/v1/payment_intents");
    httpService.setUsername(stripeSecretKey);
    httpService.setPassword("");

    httpService.addParam(type="formfield", name="amount", value=totalAmountCents);
    httpService.addParam(type="formfield", name="currency", value="usd");
    httpService.addParam(type="formfield", name="automatic_payment_methods[enabled]", value="true");

    if (hasStripeConnect) {
        // SP-SM: Add grant owner fee to platform fee (Payfrit collects, then transfers to owner)
        effectivePlatformFeeCents = totalPlatformFeeCents + grantOwnerFeeCents;
        httpService.addParam(type="formfield", name="application_fee_amount", value=effectivePlatformFeeCents);
        httpService.addParam(type="formfield", name="transfer_data[destination]", value=qBusiness.StripeAccountID);
    }

    httpService.addParam(type="formfield", name="metadata[order_id]", value=orderID);
    httpService.addParam(type="formfield", name="metadata[business_id]", value=businessID);

    // SP-SM: Store grant metadata for webhook transfer
    if (grantOwnerFeeCents > 0) {
        httpService.addParam(type="formfield", name="metadata[grant_id]", value=grantID);
        httpService.addParam(type="formfield", name="metadata[grant_owner_business_id]", value=grantOwnerBusinessID);
        httpService.addParam(type="formfield", name="metadata[grant_owner_fee_cents]", value=grantOwnerFeeCents);
    }
    httpService.addParam(type="formfield", name="description", value="Order ###orderID# at #qBusiness.Name#");

    if (customerEmail != "") {
        httpService.addParam(type="formfield", name="receipt_email", value=customerEmail);
    }

    result = httpService.send().getPrefix();
    piData = deserializeJSON(result.fileContent);

    if (structKeyExists(piData, "error")) {
        response["ERROR"] = piData.error.message;
        writeOutput(serializeJSON(response));
        abort;
    }

    // Fees are calculated dynamically, not stored in DB

    // Link PaymentIntent to worker payout ledger (if a ledger row exists for this order's task)
    try {
        queryExecute("
            UPDATE WorkPayoutLedgers wpl
            INNER JOIN Tasks t ON t.ID = wpl.TaskID AND t.OrderID = :orderID
            SET wpl.StripePaymentIntentID = :piID
            WHERE wpl.Status = 'pending_charge'
              AND wpl.StripePaymentIntentID IS NULL
        ", {
            orderID: orderID,
            piID: piData.id
        }, { datasource: "payfrit" });
    } catch (any e) {
        // Non-fatal: ledger row may not exist yet (task not completed before payment)
        writeLog(file="stripe_webhooks", text="Ledger link skipped for order #orderID#: #e.message#");
    }

    // Create Checkout Session for web-based payment (iOS app uses this)
    checkoutService = new http();
    checkoutService.setMethod("POST");
    checkoutService.setUrl("https://api.stripe.com/v1/checkout/sessions");
    checkoutService.setUsername(stripeSecretKey);
    checkoutService.setPassword("");

    checkoutService.addParam(type="formfield", name="mode", value="payment");
    checkoutService.addParam(type="formfield", name="line_items[0][price_data][currency]", value="usd");
    checkoutService.addParam(type="formfield", name="line_items[0][price_data][product_data][name]", value="Order ###orderID# at #qBusiness.Name#");
    checkoutService.addParam(type="formfield", name="line_items[0][price_data][unit_amount]", value=totalAmountCents);
    checkoutService.addParam(type="formfield", name="line_items[0][quantity]", value="1");
    checkoutService.addParam(type="formfield", name="success_url", value="payfrit://stripe-redirect?success=true&order_id=#orderID#");
    checkoutService.addParam(type="formfield", name="cancel_url", value="payfrit://stripe-redirect?success=false&error=cancelled&order_id=#orderID#");
    checkoutService.addParam(type="formfield", name="metadata[order_id]", value=orderID);
    checkoutService.addParam(type="formfield", name="metadata[business_id]", value=businessID);

    if (hasStripeConnect) {
        effectivePlatformFeeCents = totalPlatformFeeCents + grantOwnerFeeCents;
        checkoutService.addParam(type="formfield", name="payment_intent_data[application_fee_amount]", value=effectivePlatformFeeCents);
        checkoutService.addParam(type="formfield", name="payment_intent_data[transfer_data][destination]", value=qBusiness.StripeAccountID);
    }

    checkoutResult = checkoutService.send().getPrefix();
    checkoutData = deserializeJSON(checkoutResult.fileContent);

    checkoutUrl = "";
    if (structKeyExists(checkoutData, "url")) {
        checkoutUrl = checkoutData.url;
    } else if (structKeyExists(checkoutData, "error")) {
        // Log checkout error but don't fail - client_secret still works for SDK
        writeLog(file="stripe_webhooks", text="Checkout session error: #checkoutData.error.message#");
    }

    response["OK"] = true;
    response["CLIENT_SECRET"] = piData.client_secret;
    response["PAYMENT_INTENT_ID"] = piData.id;
    response["PUBLISHABLE_KEY"] = application.stripePublishableKey ?: "pk_test_sPBNzSyJ9HcEPJGC7dSo8NqN";
    response["CHECKOUT_URL"] = checkoutUrl;
    response["FEE_BREAKDOWN"] = {
        "SUBTOTAL": subtotal,
        "TAX": tax,
        "TIP": tip,
        "DELIVERY_FEE": deliveryFee,
        "PAYFRIT_FEE": payfritCustomerFee,
        "CARD_FEE": cardFee,
        "TOTAL": totalCustomerPays,
        "GRANT_OWNER_FEE_CENTS": grantOwnerFeeCents
    };
    response["STRIPE_CONNECT_ENABLED"] = hasStripeConnect;

} catch (any e) {
    response["ERROR"] = e.message;
    response["DETAIL"] = e.detail ?: "";
}

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