"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createCodOrder = exports.addAddress = exports.getUserOrders = exports.stripeWebhook = exports.createOrder = exports.createStripeSession = void 0;
const stripe_1 = __importDefault(require("stripe"));
const db_1 = __importDefault(require("../DB/db"));
const asyncHandler_1 = __importDefault(require("../utils/asyncHandler"));
const crypto_1 = __importDefault(require("crypto"));
const apiResponse_1 = __importDefault(require("../utils/apiResponse"));
const apiError_1 = __importDefault(require("../utils/apiError"));
const stripe = new stripe_1.default(process.env.STRIPE_SECRET_KEY, {
    apiVersion: '2025-12-15.clover',
});
// --- Create Stripe Checkout Session ---
exports.createStripeSession = (0, asyncHandler_1.default)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
    var _a, _b;
    const userId = ((_a = req.user) === null || _a === void 0 ? void 0 : _a.id) || req.body.userId;
    if (!userId) {
        throw new apiError_1.default(401, "Unauthorized request");
    }
    // 1. Fetch Cart Items
    const cart = yield db_1.default.cart.findUnique({
        where: { userId },
        include: {
            items: {
                include: {
                    product: true,
                    productVariant: true,
                },
            },
        },
    });
    if (!cart || cart.items.length === 0) {
        throw new apiError_1.default(400, "Cart is empty");
    }
    // 2. Prepare Line Items for Stripe
    const line_items = cart.items.map((item) => {
        var _a;
        const basePrice = Number(item.product.price);
        const variantDiff = Number(((_a = item.productVariant) === null || _a === void 0 ? void 0 : _a.priceDiff) || 0);
        const unitAmount = Math.round((basePrice + variantDiff) * 100); // Stripe expects amounts in cents (paise)
        // Build description
        const description = item.productVariant
            ? `Size: ${item.productVariant.size}, Color: ${item.productVariant.color}`
            : "Standard";
        return {
            price_data: {
                currency: "usd", // Change to "inr" for Rupees
                product_data: {
                    name: item.product.name,
                    description: description,
                    images: item.product.images ? [item.product.images[0]] : [],
                },
                unit_amount: unitAmount,
            },
            quantity: item.quantity,
        };
    });
    // 3. Calculate Totals for Shipping/Tax Logic (Optional but good for metadata)
    const subtotal = cart.items.reduce((sum, item) => {
        var _a;
        const p = Number(item.product.price) + Number(((_a = item.productVariant) === null || _a === void 0 ? void 0 : _a.priceDiff) || 0);
        return sum + p * item.quantity;
    }, 0);
    // Add Shipping Line Item (Free if > 100)
    const shippingCost = subtotal > 100 ? 0 : 20;
    if (shippingCost > 0) {
        line_items.push({
            price_data: {
                currency: "usd",
                product_data: {
                    name: "Standard Shipping",
                },
                unit_amount: shippingCost * 100,
            },
            quantity: 1,
        });
    }
    // Add Tax Line Item (18%)
    const taxAmount = Math.round(subtotal * 0.18 * 100);
    if (taxAmount > 0) {
        line_items.push({
            price_data: {
                currency: "usd",
                product_data: {
                    name: "GST / Tax (18%)",
                },
                unit_amount: taxAmount,
            },
            quantity: 1,
        });
    }
    // 4. Create Session
    const session = yield stripe.checkout.sessions.create({
        payment_method_types: ["card"],
        line_items,
        mode: "payment",
        success_url: `${process.env.FRONTEND_URL}/success?session_id={CHECKOUT_SESSION_ID}`,
        cancel_url: `${process.env.FRONTEND_URL}/checkout`,
        customer_email: (_b = req.user) === null || _b === void 0 ? void 0 : _b.email, // Pre-fill email if available
        metadata: {
            userId: userId,
            cartId: cart.id,
            source: "SSBN_Web",
        },
    });
    return res.status(200).json(new apiResponse_1.default(200, { url: session.url, sessionId: session.id }, "Stripe session created"));
}));
// ----------------------------
// Create an Order & Payment
// ----------------------------
const createOrder = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
    try {
        const { userId, addressId, paymentMethod } = req.body;
        if (!userId)
            return res.status(400).json({ message: 'User ID required' });
        // 1️⃣ Fetch user's cart
        const cart = yield db_1.default.cart.findUnique({
            where: { userId },
            include: { items: { include: { product: true, variant: true } } },
        });
        if (!cart || cart.items.length === 0)
            return res.status(400).json({ message: 'Cart is empty' });
        // 2️⃣ Calculate totals
        const subtotal = cart.items.reduce((sum, item) => {
            var _a;
            const price = ((_a = item.variant) === null || _a === void 0 ? void 0 : _a.priceDiff)
                ? item.product.price + item.variant.priceDiff
                : item.product.price;
            return sum + Number(price) * item.quantity;
        }, 0);
        const shippingCost = 0;
        const tax = subtotal * 0.05; // 5% tax example
        const total = subtotal + shippingCost + tax;
        // 3️⃣ Create order
        const orderNumber = `SSBN-${Math.floor(100000 + Math.random() * 900000)}`;
        const order = yield db_1.default.order.create({
            data: {
                userId,
                orderNumber,
                subtotal,
                shippingCost,
                tax,
                total,
                addressId,
                items: {
                    create: cart.items.map((item) => {
                        var _a, _b, _c, _d;
                        return ({
                            productId: item.product.id,
                            productName: item.product.name,
                            productImage: item.product.images[0],
                            sku: (_a = item.variant) === null || _a === void 0 ? void 0 : _a.sku,
                            size: (_b = item.variant) === null || _b === void 0 ? void 0 : _b.size,
                            color: (_c = item.variant) === null || _c === void 0 ? void 0 : _c.color,
                            price: ((_d = item.variant) === null || _d === void 0 ? void 0 : _d.priceDiff)
                                ? item.product.price + item.variant.priceDiff
                                : item.product.price,
                            quantity: item.quantity,
                            variantId: item.variantId,
                        });
                    }),
                },
            },
        });
        // 4️⃣ Handle Payment Intent if Stripe
        if (paymentMethod === 'STRIPE') {
            const paymentIntent = yield stripe.paymentIntents.create({
                amount: Math.round(total * 100), // in paise
                currency: 'USD',
                metadata: { orderId: order.id },
            });
            // Create payment record
            yield db_1.default.payment.create({
                data: {
                    orderId: order.id,
                    provider: 'STRIPE',
                    status: 'PENDING',
                    amount: total,
                    transactionId: paymentIntent.id,
                },
            });
            return res.json({
                success: true,
                clientSecret: paymentIntent.client_secret,
                orderId: order.id,
            });
        }
        else if (paymentMethod === 'COD') {
            // Cash on Delivery
            yield db_1.default.payment.create({
                data: {
                    orderId: order.id,
                    provider: 'COD',
                    status: 'PENDING',
                    amount: total,
                },
            });
            return res.json({ success: true, orderId: order.id });
        }
        return res.status(400).json({ message: 'Invalid payment method' });
    }
    catch (err) {
        console.error(err);
        return res.status(500).json({ message: err.message });
    }
});
exports.createOrder = createOrder;
// --- Webhook Handler ---
const stripeWebhook = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
    var _a, _b;
    const sig = req.headers["stripe-signature"];
    let event;
    try {
        event = stripe.webhooks.constructEvent(req.body, // Raw buffer
        sig, process.env.STRIPE_WEBHOOK_SECRET);
    }
    catch (err) {
        console.error(`Webhook signature verification failed: ${err.message}`);
        return res.status(400).send(`Webhook Error: ${err.message}`);
    }
    if (event.type === "checkout.session.completed") {
        const session = event.data.object;
        // Retrieve metadata
        const userId = (_a = session.metadata) === null || _a === void 0 ? void 0 : _a.userId;
        const addressId = (_b = session.metadata) === null || _b === void 0 ? void 0 : _b.addressId;
        if (userId && addressId) {
            try {
                yield fulfillOrder(userId, addressId, session);
                console.log("Order fulfilled successfully via Webhook");
            }
            catch (error) {
                console.error("Error fulfilling order:", error);
                return res.status(500).json({ error: "Failed to fulfill order" });
            }
        }
    }
    res.json({ received: true });
});
exports.stripeWebhook = stripeWebhook;
// --- Fulfill Order Helper ---
function fulfillOrder(userId, addressId, session) {
    return __awaiter(this, void 0, void 0, function* () {
        // 1. Idempotency Check
        const existingOrder = yield db_1.default.order.findFirst({
            where: { payment: { transactionId: session.id } }
        });
        if (existingOrder)
            return;
        // 2. Fetch User's Cart
        const cart = yield db_1.default.cart.findUnique({
            where: { userId },
            include: {
                items: {
                    include: { product: true, productVariant: true },
                },
            },
        });
        if (!cart || cart.items.length === 0) {
            console.error(`Cart empty for user ${userId}`);
            return;
        }
        // 3. Transaction
        yield db_1.default.$transaction((tx) => __awaiter(this, void 0, void 0, function* () {
            var _a;
            // Prepare Order Items with Snapshot Data (Image, SKU, etc.)
            const orderItemsData = cart.items.map((item) => {
                var _a, _b, _c, _d, _e, _f, _g, _h, _j;
                const basePrice = Number(item.product.price);
                const diff = Number(((_a = item.productVariant) === null || _a === void 0 ? void 0 : _a.priceDiff) || 0);
                const price = basePrice + diff;
                return {
                    // Relations
                    productId: item.productId,
                    variantId: item.variantId,
                    // 🔥 SNAPSHOT DATA (Fixed to match COD Controller)
                    productName: item.product.name,
                    productImage: (_c = (_b = item.product.images) === null || _b === void 0 ? void 0 : _b[0]) !== null && _c !== void 0 ? _c : null, // ✅ Image Added
                    sku: (_e = (_d = item.productVariant) === null || _d === void 0 ? void 0 : _d.sku) !== null && _e !== void 0 ? _e : null,
                    size: (_g = (_f = item.productVariant) === null || _f === void 0 ? void 0 : _f.size) !== null && _g !== void 0 ? _g : null,
                    color: (_j = (_h = item.productVariant) === null || _h === void 0 ? void 0 : _h.color) !== null && _j !== void 0 ? _j : null,
                    price,
                    quantity: item.quantity,
                };
            });
            // Calculate Costs from Session
            const totalAmount = session.amount_total ? session.amount_total / 100 : 0;
            const subtotal = session.amount_subtotal ? session.amount_subtotal / 100 : 0;
            const shippingCost = ((_a = session.total_details) === null || _a === void 0 ? void 0 : _a.amount_shipping) ? session.total_details.amount_shipping / 100 : 0;
            const tax = 0; // Or calculate manually if Stripe doesn't provide breakdown in metadata
            // Create Order
            yield tx.order.create({
                data: {
                    user: { connect: { id: userId } },
                    shippingAddress: { connect: { id: addressId } },
                    orderNumber: `SSBN-${crypto_1.default.randomInt(10001, 99999)}`,
                    subtotal,
                    shippingCost,
                    tax,
                    total: totalAmount,
                    status: "PAID",
                    isPaid: true,
                    // Payment Relation
                    payment: {
                        create: {
                            provider: "STRIPE", // or "CARD"
                            status: "PAID",
                            amount: totalAmount,
                            transactionId: session.id,
                        }
                    },
                    // Items Relation
                    items: {
                        create: orderItemsData,
                    },
                },
            });
            // Decrement Stock
            for (const item of cart.items) {
                if (item.variantId) {
                    yield tx.productVariant.update({
                        where: { id: item.variantId },
                        data: { stock: { decrement: item.quantity } },
                    });
                }
            }
            // Clear Cart
            yield tx.cartItem.deleteMany({
                where: { cartId: cart.id },
            });
        }));
    });
}
// ----------------------------
// Get User Orders
// ----------------------------
const getUserOrders = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
    const { userId } = req.params;
    const orders = yield db_1.default.order.findMany({
        where: { userId },
        include: { items: true, payment: true, shippingAddress: true },
        orderBy: { createdAt: 'desc' },
    });
    res.json({ success: true, orders });
});
exports.getUserOrders = getUserOrders;
// ----------------------------
// Add a new address
// ----------------------------
const addAddress = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
    const { userId, type, street, city, state, zipCode, country, phone, isDefault } = req.body;
    if (!userId || !street || !city || !state || !zipCode || !country || !phone) {
        return res.status(400).json({ message: 'All required fields must be filled' });
    }
    try {
        // If new address is default, reset existing default
        if (isDefault) {
            yield db_1.default.address.updateMany({
                where: { userId, isDefault: true },
                data: { isDefault: false },
            });
        }
        const address = yield db_1.default.address.create({
            data: {
                userId,
                type: type || 'HOME',
                street,
                city,
                state,
                zipCode,
                country,
                phone,
                isDefault: isDefault || false,
            },
        });
        res.json({ success: true, address });
    }
    catch (err) {
        console.error(err);
        res.status(500).json({ message: err.message });
    }
});
exports.addAddress = addAddress;
// --- Create COD Order ---
exports.createCodOrder = (0, asyncHandler_1.default)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
    const { userId } = req.params;
    const { addressId } = req.body;
    if (!userId || !addressId) {
        throw new apiError_1.default(false, 400, "User ID and Address ID are required");
    }
    const orderNumber = `SSBN-${crypto_1.default.randomInt(10001, 99999)}`;
    // 1. Fetch Cart
    const cart = yield db_1.default.cart.findUnique({
        where: { userId },
        include: {
            items: {
                include: {
                    product: true,
                    productVariant: true,
                },
            },
        },
    });
    if (!cart || cart.items.length === 0) {
        throw new apiError_1.default(false, 400, "Cart is empty");
    }
    // 2. Transaction
    const order = yield db_1.default.$transaction((tx) => __awaiter(void 0, void 0, void 0, function* () {
        let subtotal = 0;
        const orderItemsData = cart.items.map((item) => {
            var _a, _b, _c, _d, _e, _f, _g, _h, _j;
            const basePrice = Number(item.product.price);
            const diff = Number(((_a = item.productVariant) === null || _a === void 0 ? void 0 : _a.priceDiff) || 0);
            const price = basePrice + diff;
            const total = price * item.quantity;
            subtotal += total;
            return {
                // relations
                productId: item.productId,
                variantId: item.variantId,
                // 🔥 SNAPSHOT DATA
                productName: item.product.name,
                productImage: (_c = (_b = item.product.images) === null || _b === void 0 ? void 0 : _b[0]) !== null && _c !== void 0 ? _c : null, // ✅ IMAGE FIX
                sku: (_e = (_d = item.productVariant) === null || _d === void 0 ? void 0 : _d.sku) !== null && _e !== void 0 ? _e : null,
                size: (_g = (_f = item.productVariant) === null || _f === void 0 ? void 0 : _f.size) !== null && _g !== void 0 ? _g : null,
                color: (_j = (_h = item.productVariant) === null || _h === void 0 ? void 0 : _h.color) !== null && _j !== void 0 ? _j : null,
                price,
                quantity: item.quantity,
            };
        });
        const shippingCost = subtotal > 100 ? 0 : 20;
        const tax = subtotal * 0.18;
        const totalAmount = subtotal + shippingCost + tax;
        const newOrder = yield tx.order.create({
            data: {
                orderNumber,
                user: { connect: { id: userId } },
                shippingAddress: { connect: { id: addressId } },
                subtotal,
                shippingCost,
                tax,
                total: totalAmount,
                status: "PENDING",
                isPaid: false,
                payment: {
                    create: {
                        provider: "CASH_ON_DELIVERY",
                        amount: totalAmount,
                        status: "PENDING",
                    },
                },
                items: {
                    create: orderItemsData,
                },
            },
        });
        // 3. Decrement Stock
        for (const item of cart.items) {
            if (item.variantId) {
                yield tx.productVariant.update({
                    where: { id: item.variantId },
                    data: { stock: { decrement: item.quantity } },
                });
            }
        }
        // 4. Clear Cart
        yield tx.cartItem.deleteMany({
            where: { cartId: cart.id },
        });
        return newOrder;
    }));
    // 5. Return Order with Items
    const orderWithItems = yield db_1.default.order.findUnique({
        where: { id: order.id },
        include: {
            items: true,
            payment: true,
        },
    });
    return res.status(201).json(new apiResponse_1.default(true, 201, "COD order placed successfully", {
        orderId: orderWithItems === null || orderWithItems === void 0 ? void 0 : orderWithItems.id,
        orderNumber: orderWithItems === null || orderWithItems === void 0 ? void 0 : orderWithItems.orderNumber,
        total: orderWithItems === null || orderWithItems === void 0 ? void 0 : orderWithItems.total,
        items: orderWithItems === null || orderWithItems === void 0 ? void 0 : orderWithItems.items.map((item) => ({
            name: item.productName,
            image: item.productImage, // ✅ IMAGE RETURNED
            sku: item.sku,
            price: Number(item.price),
            qty: item.quantity,
            total: Number(item.price) * item.quantity,
        })),
    }));
}));
