const { bigcommerceApiOAuth, serverBaseURL, bigcommerceStoreHash } = require("../config.js")
let { clearSSRCache, createTibiCustomer, updateTibiCustomer } = require("../lib/utils")
const {
    getProductImages,
    getOrderProductsById,
    getProductById,
    getCustomerById,
    getOrderById,
    createInternalOrderObject,
} = require("../lib/bigcommerceRestAPI.js")
const { createPrintfulWebhook, getPrintfulOrderShipments } = require("../lib/printfulRestAPI.js")
const { postPurchase } = require("../lib/facebookRestAPI.js")
;(function () {
    const data = context.data
    if (context?.user?.auth()?.id) {
        if (context.data.type === "printful") {
            createPrintfulWebhook(context.data.scope)
            return
        } else {
            let url = `https://api.bigcommerce.com/stores/${bigcommerceStoreHash}/v3/hooks`

            let options = {
                method: "POST",
                headers: { "Content-Type": "application/json", "X-Auth-Token": bigcommerceApiOAuth },
                body: JSON.stringify({
                    scope: context?.data?.scope,
                    destination: `${serverBaseURL}webhook`,
                    is_active: context?.data?.active,
                    events_history_enabled: true,
                    headers: { token: "super_secure_and_extremely_secret_big_commerce_webhook_token_123" },
                }),
            }

            const response = context.http.fetch(url, options).body.json()
            const hookResponse = {
                data: context.data,
            }
            // @ts-ignore
            hookResponse.data.webhookId = response.data.id
            return hookResponse
        }
    }
    if (data) {
        if (data?.type === "order_updated") {
            const bigCommerceOrderId = data?.data?.order?.external_id
            const order = context.db.find("bigCommerceOrder", {
                filter: {
                    bigCommerceId: Number(bigCommerceOrderId),
                },
            })[0]
            if (order) {
                context.db.update("bigCommerceOrder", order.id, {
                    status: data?.data?.order?.status,
                    statusSetAt: new Date().toISOString(),
                })
            }
            throw {
                status: 200,
                data: {
                    message: "",
                },
            }
        } else if (data?.type == "shipment_sent") {
            const bigCommerceOrderId = data?.data?.order?.external_id

            const printfulOrderShipments = getPrintfulOrderShipments(Number(bigCommerceOrderId))

            const order = context.db.find("bigCommerceOrder", {
                filter: {
                    bigCommerceId: Number(bigCommerceOrderId),
                },
            })[0]
            if (order) {
                context.db.update("bigCommerceOrder", order.id, {
                    shipments: (printfulOrderShipments || []).map((shipped) => {
                        return {
                            trackingUrl: shipped.tracking_url,
                            trackingNumber: data?.data?.shipment?.tracking_number,
                            carrier: shipped.carrier,
                            sentAt: new Date(),
                        }
                    }),
                })
            }
            throw {
                status: 200,
                data: {
                    message: "",
                },
            }
        } else if (data?.scope?.includes("product")) {
            if (data.scope.includes("product/deleted")) {
                handleProductDeleted(data.data.id)
                clearSSRCache()
            } else {
                const product = getProductById(data?.data?.id)
                const productImage = getProductImages(data?.data?.id)

                if (data.scope.includes("product/created") && product?.id) {
                    handleProductCreateOrUpdate(product, productImage)
                }
                if (data.scope.includes("product/updated") && product?.id) {
                    handleProductCreateOrUpdate(product, productImage)
                }
                clearSSRCache()
            }
            throw {
                status: 200,
                data: {
                    message: "",
                },
            }
        } else if (data?.scope?.includes("order")) {
            if (data.scope.includes("order/statusUpdated")) {
                if (data.data.status.new_status_id == 11) {
                    const internalOrderReference = createInternalOrderObject(data.data.id)
                    // make sure the order doesn't already exist
                    const orderExists = context.db.find("bigCommerceOrder", {
                        filter: {
                            bigCommerceId: Number(data.data.id),
                        },
                    })
                    if (!orderExists.length) context.db.create("bigCommerceOrder", internalOrderReference)
                    else context.db.update("bigCommerceOrder", orderExists[0].id, internalOrderReference)
                    /*
                    not necessary for now, as bigcommerce itself takes care of it
                    try {
                        if (!orderExists) {
                            postPurchase(internalOrderReference.cost.replace(",", "."))
                        }
                    } catch (e) {
                        console.log(e)
                    }*/
                } else {
                    const order = context.db.find("bigCommerceOrder", {
                        filter: {
                            bigCommerceId: data.data.id,
                        },
                    })[0]

                    /**
                     *
                     * @param {any} orderStatus
                     * @returns {PrintfulStates | false}
                     */
                    function mapOrderStatusToPrintful(orderStatus) {
                        switch (orderStatus.new_status_id) {
                            case 0:
                            case 1:
                            case 7:
                            case 11:
                                return "draft" // Unvollständig
                            case 6:
                                return "failed" // Abgelehnt
                            case 10:
                                return "fulfilled" // Versandt, Versand ausstehend, Abgeschlossen
                            case 3:
                                return "partial" // Teilweise Versandt, Teilweise erstattet
                            case 12:
                            case 13:
                                return "onhold" // Manuelle Überprüfung erforderlich, Umstritten (closest match)
                            default:
                                return false
                        }
                    }
                    if (order && mapOrderStatusToPrintful(data.data.status) !== false) {
                        context.db.update("bigCommerceOrder", order.id, {
                            status: mapOrderStatusToPrintful(data.data.status),
                            statusSetAt: new Date().toISOString(),
                        })
                    }
                }
            }
            throw {
                status: 200,
                data: {
                    message: "",
                },
            }
        } else if (data?.scope?.includes("customer")) {
            let internalCustomer
            if (data.data?.id)
                /** @type {Customer} */
                internalCustomer =
                    context.db.find("bigCommerceCustomer", {
                        filter: {
                            bigCommerceId: data.data.id,
                        },
                    })?.[0] || null

            if (data.scope.includes("customer/deleted") && !!internalCustomer) {
                context.db.delete("bigCommerceCustomer", internalCustomer.id)
            } else {
                const customer = getCustomerById(data?.data?.id)

                if (!internalCustomer && customer?.id) {
                    createTibiCustomer(customer)
                } else if (data.scope.includes("customer/updated") && !!internalCustomer) {
                    updateTibiCustomer(customer, internalCustomer)
                }
            }
            throw {
                status: 200,
                data: {
                    message: "",
                },
            }
        } else
            throw {
                status: 403,
                error: "Forbidden",
            }
    } else
        throw {
            status: 403,
            error: "Forbidden",
        }
})()

/**
 * Handles both product creation and update by checking if the product exists and then
 * creating or updating the record accordingly.
 *
 * @param {V2OrderProductsResponseBase} [product] The product data.
 * @param { ProductImage[]} [productImage] The product image data.
 */
function handleProductCreateOrUpdate(product, productImage) {
    const internalProduct =
        context.db.find("bigCommerceProduct", {
            filter: {
                bigCommerceId: Number(product?.id),
            },
        })?.[0] || null
    if (internalProduct) {
        // If the product exists, update it.
        context.db.update("bigCommerceProduct", internalProduct.id || "", {
            productName: product?.name_customer || product?.name,
            bigCommerceSKU: product?.sku,
            previewImage: productImage?.[0]?.url_thumbnail,
            bigCommerceId: Number(product?.id),
        })
    } else {
        // If the product does not exist, create it.
        context.db.create("bigCommerceProduct", {
            productName: product?.name_customer || product?.name,
            bigCommerceSKU: product?.sku,
            previewImage: productImage?.[0]?.url_thumbnail,
            bigCommerceId: Number(product?.id),
        })
    }
}

/**
 * Handles product deletion by removing the product record if it exists.
 * @param { V2OrderProductsResponseBase  } [id] The product data to delete.
 */
function handleProductDeleted(id) {
    const internalProduct = context.db.find("bigCommerceProduct", {
        filter: {
            bigCommerceId: Number(id),
        },
    })[0]
    if (internalProduct) {
        context.db.delete("bigCommerceProduct", internalProduct.id || "")
    }
}
