"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.topUpUserWallet = exports.purchaseTimeSlotWithWallet = exports.purchaseFreeTimeSlot = exports.createOrder = exports.confirmPayment = exports.PaymentMethod = exports.PaymentStatus = void 0;
const functions = require("firebase-functions");
const firebase_admin_1 = require("firebase-admin");
const collections_1 = require("./collections");
const notification_function_1 = require("./notification-function");
const https_1 = require("firebase-functions/v1/https");
const collections_2 = require("./collections");
const constants_1 = require("./constants");
const custom_error_1 = require("./utils/custom_error");
var PaymentStatus;
(function (PaymentStatus) {
    PaymentStatus["PaymentSuccess"] = "payment_success";
    PaymentStatus["PaymentFail"] = "payment_failed";
})(PaymentStatus = exports.PaymentStatus || (exports.PaymentStatus = {}));
var PaymentMethod;
(function (PaymentMethod) {
    PaymentMethod["Stripe"] = "stripe";
    PaymentMethod["Paystack"] = "paystack";
    PaymentMethod["Razorpay"] = "razorpay";
    PaymentMethod["PayMob"] = "paymob";
    PaymentMethod["Midtrans"] = "midtrans";
})(PaymentMethod = exports.PaymentMethod || (exports.PaymentMethod = {}));
var TimeSlotStatus;
(function (TimeSlotStatus) {
    TimeSlotStatus["booked"] = "booked";
    TimeSlotStatus["refund"] = "refund";
    TimeSlotStatus["cancel"] = "cancel";
})(TimeSlotStatus || (TimeSlotStatus = {}));
/**
 * Confirm payment, confirm the payment made by user, will set the status to booked and add the Appointment to Doctor Tab and client tab,
 * usually this get called when webhook successfully payment get called
 * @param {ConfirmPayment} confirmPayment you need to create new ConfirmPayment object base on previous ordered timeslot
 */
async function confirmPayment(confirmPayment) {
    try {
        await collections_1.orderCol.doc(confirmPayment.orderId).update({
            charged: true,
            amount: confirmPayment.amount,
            status: confirmPayment.paymentStatus,
            currency: confirmPayment.currency,
            fee: confirmPayment.fee,
            paymentMethod: confirmPayment.paymentMethod,
            paymentType: confirmPayment.paymentType,
        });
        await collections_2.timeSlotCol.doc(confirmPayment.timeSlotId).update({
            charged: true,
            available: false,
            bookByWho: confirmPayment.bookByWho,
            status: TimeSlotStatus.booked,
            doctor: confirmPayment.doctor,
            purchaseTime: firebase_admin_1.firestore.Timestamp.fromDate(new Date()),
        });
        await (0, notification_function_1.orderedTimeslotNotification)(confirmPayment.doctorId);
    }
    catch (error) {
        throw error;
    }
}
exports.confirmPayment = confirmPayment;
/**
 * create an order with status not pay, later once client successfully made the payment, you can change the order status to pay
 * @param timeSlotId timeslot id that client wanted to buy
 * @param userId user id who buy this timeslot
 * @param orderId you can set order id, you get this from your payment provider, like id transaction or reference id, that later you can use to find this particular order id, usually from webhook
 */
async function createOrder(timeSlotId, userId, orderId) {
    try {
        const newOrder = {
            charged: false,
            status: collections_1.OrderStatus.notPay,
            timeSlotId: timeSlotId,
            userId: userId,
            createdAt: firebase_admin_1.firestore.Timestamp.fromDate(new Date()),
        };
        await collections_1.orderCol.doc(orderId).create(newOrder);
        console.log("add new order");
    }
    catch (error) {
        throw error;
    }
}
exports.createOrder = createOrder;
/**
 * purchase free timeslot, this function get calle by client when the timeslot price is 0
 * if actual price is not 0 will return a https error
 * @param userId string of user id that wanto purchase this timeslot
 * @param timeSlotId timeSlotId that user wanto purchase
 * @return will return true if success success
 */
exports.purchaseFreeTimeSlot = functions.https.onCall(async (request, response) => {
    try {
        let { userId, timeSlotId } = request;
        let purchasedTimeSlot = await collections_2.timeSlotCol.doc(timeSlotId).get();
        let purchasedTimeslotData = purchasedTimeSlot.data();
        console.log(JSON.stringify(purchasedTimeslotData));
        if (!purchasedTimeslotData) {
            throw new https_1.HttpsError("not-found", "TimeSlot not found, please check the timeslot again");
        }
        let amount = purchasedTimeslotData.price;
        if (amount > 0) {
            throw new https_1.HttpsError("permission-denied", "the timeslot price is not 0 or free, please choose another timeslot");
        }
        //Get user info who book this timeslot
        let bookByWho = await collections_1.usersCol.doc(userId).get();
        let bookByWhoData = bookByWho.data();
        if (!bookByWhoData) {
            throw new https_1.HttpsError("not-found", "User book by who not found");
        }
        //Get doctor detail data
        let doctor = await collections_2.doctorCol.doc(purchasedTimeslotData.doctorId).get();
        let doctorData = doctor.data();
        if (!doctorData) {
            throw new https_1.HttpsError("not-found", "Doctor Data not found");
        }
        await purchasedTimeSlot.ref.update({
            charged: true,
            available: false,
            bookByWho: {
                userId: userId,
                displayName: bookByWhoData.displayName,
                photoUrl: bookByWhoData.photoUrl ? bookByWhoData.photoUrl : "",
            },
            status: TimeSlotStatus.booked,
            doctor: {
                doctorName: doctorData.doctorName,
                doctorPicture: doctorData.doctorPicture,
            },
            purchaseTime: firebase_admin_1.firestore.Timestamp.fromDate(new Date()),
        });
        const orderData = await collections_1.orderCol.add({
            createdAt: firebase_admin_1.firestore.Timestamp.fromDate(new Date()),
            timeSlotId: timeSlotId,
            userId: request.userId,
            charged: true,
            stripePaymentId: "",
            amount: amount,
            status: collections_1.OrderStatus.pay,
            linkReceipt: "",
            currency: constants_1.CURRENCY,
        });
        await (0, notification_function_1.orderedTimeslotNotification)(doctor.id);
        await (0, notification_function_1.paymentSuccessNotification)(request.userId, orderData.id);
        return true;
    }
    catch (e) {
        throw e;
    }
});
exports.purchaseTimeSlotWithWallet = functions.https.onCall(async (request, context) => {
    var _a, _b, _c, _d;
    try {
        const { userId, timeSlotId } = request;
        console.log("request", JSON.stringify(request));
        const userWallet = await collections_1.userWalletCol.doc(userId).get();
        const userWalletHisotryRef = (0, collections_1.userWalletHistoryCol)(userId);
        const purchasedTimeSlot = await collections_2.timeSlotCol.doc(timeSlotId).get();
        let purchasedTimeslotData = purchasedTimeSlot.data();
        console.log(JSON.stringify(purchasedTimeslotData));
        //check if the wallet amount is sufficient to purchase this timeslot
        if (((_a = userWallet === null || userWallet === void 0 ? void 0 : userWallet.data()) === null || _a === void 0 ? void 0 : _a.balance) && ((_b = purchasedTimeSlot === null || purchasedTimeSlot === void 0 ? void 0 : purchasedTimeSlot.data()) === null || _b === void 0 ? void 0 : _b.price)) {
            if (userWallet.data().balance < purchasedTimeSlot.data().price) {
                throw new functions.https.HttpsError("failed-precondition", "User wallet balance is not sufficient to purchase this timeslot");
            }
        }
        /// Purchase timeslot
        if (!purchasedTimeslotData) {
            throw new https_1.HttpsError("not-found", "TimeSlot not found, please check the timeslot again");
        }
        //Get user info who book this timeslot
        let bookByWho = await collections_1.usersCol.doc(userId).get();
        let bookByWhoData = bookByWho.data();
        if (!bookByWhoData) {
            throw new https_1.HttpsError("not-found", "User book by who not found");
        }
        //Get doctor detail data
        let doctor = await collections_2.doctorCol.doc(purchasedTimeslotData.doctorId).get();
        let doctorData = doctor.data();
        let amount = purchasedTimeslotData.price;
        if (!doctorData) {
            throw new https_1.HttpsError("not-found", "Doctor Data not found");
        }
        await purchasedTimeSlot.ref.update({
            charged: true,
            available: false,
            bookByWho: {
                userId: userId,
                displayName: bookByWhoData.displayName,
                photoUrl: bookByWhoData.photoUrl ? bookByWhoData.photoUrl : "",
            },
            status: TimeSlotStatus.booked,
            doctor: {
                doctorName: doctorData.doctorName,
                doctorPicture: doctorData.doctorPicture,
            },
            purchaseTime: firebase_admin_1.firestore.Timestamp.fromDate(new Date()),
        });
        await collections_1.orderCol.add({
            createdAt: firebase_admin_1.firestore.Timestamp.fromDate(new Date()),
            timeSlotId: timeSlotId,
            userId: request.userId,
            charged: true,
            stripePaymentId: "",
            amount: amount,
            status: collections_1.OrderStatus.pay,
            linkReceipt: "",
            currency: constants_1.CURRENCY,
        });
        /// Reduce use wallet
        await collections_1.userWalletCol.doc(userId).update({
            balance: firebase_admin_1.firestore.FieldValue.increment(-amount),
            updatedAt: new Date(),
        });
        /// add user wallet history with type payment
        const walletHistory = {
            initialAmount: 0,
            finalAmount: 0,
            transactionAmount: (_d = (_c = purchasedTimeSlot === null || purchasedTimeSlot === void 0 ? void 0 : purchasedTimeSlot.data()) === null || _c === void 0 ? void 0 : _c.price) !== null && _d !== void 0 ? _d : 0,
            createdAt: new Date(),
            userId: userId,
            status: "Success",
            type: "Payment",
        };
        await userWalletHisotryRef.add(walletHistory);
        return { success: true };
    }
    catch (error) {
        throw error;
    }
});
/**
 * Asynchronously top up the wallet of a user with a given amount.
 *
 * @param {string} userId - The ID of the user whose wallet is being topped up.
 * @param {number} amount - The amount to top up the user's wallet with.
 * @return {Promise<void>} A promise that resolves when the wallet has been successfully topped up.
 * @throws {Error} If there is an error toping up the user's wallet.
 */
const topUpUserWallet = async (userId, amount) => {
    try {
        const userWalletRef = collections_1.userWalletCol.doc(userId);
        const userWallet = await userWalletRef.get();
        if (userWallet.exists) {
            await userWalletRef.update({
                balance: firebase_admin_1.firestore.FieldValue.increment(amount),
            });
        }
        else {
            // throw new functions.https.HttpsError("unauthenticated", "user is not authenticated");
            throw new custom_error_1.CustomError("not-found", "User wallet not found");
        }
    }
    catch (error) {
        throw error;
    }
};
exports.topUpUserWallet = topUpUserWallet;
//# sourceMappingURL=payment-functions.js.map