/*
 * This file is part of a proprietary work.
 *
 * Copyright (c) 2025 Fossorial, Inc.
 * All rights reserved.
 *
 * This file is licensed under the Fossorial Commercial License.
 * You may not use this file except in compliance with the License.
 * Unauthorized use, copying, modification, or distribution is strictly prohibited.
 *
 * This file is not licensed under the AGPLv3.
 */

import stripe from "#private/lib/stripe";
import privateConfig from "#private/lib/config";
import logger from "@server/logger";
import createHttpError from "http-errors";
import { response } from "@server/lib/response";
import { Request, Response, NextFunction } from "express";
import HttpCode from "@server/types/HttpCode";
import Stripe from "stripe";
import { handleCustomerCreated } from "./hooks/handleCustomerCreated";
import { handleSubscriptionCreated } from "./hooks/handleSubscriptionCreated";
import { handleSubscriptionUpdated } from "./hooks/handleSubscriptionUpdated";
import { handleCustomerUpdated } from "./hooks/handleCustomerUpdated";
import { handleSubscriptionDeleted } from "./hooks/handleSubscriptionDeleted";
import { handleCustomerDeleted } from "./hooks/handleCustomerDeleted";

export async function billingWebhookHandler(
    req: Request,
    res: Response,
    next: NextFunction
): Promise<any> {
    let event: Stripe.Event = req.body;
    const endpointSecret =
        privateConfig.getRawPrivateConfig().stripe?.webhook_secret;
    if (!endpointSecret) {
        logger.warn(
            "Stripe webhook secret is not configured. Webhook events will not be priocessed."
        );
        return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, ""));
    }

    // Only verify the event if you have an endpoint secret defined.
    // Otherwise use the basic event deserialized with JSON.parse
    if (endpointSecret) {
        // Get the signature sent by Stripe
        const signature = req.headers["stripe-signature"];

        if (!signature) {
            logger.info("No stripe signature found in headers.");
            return next(
                createHttpError(
                    HttpCode.BAD_REQUEST,
                    "No stripe signature found in headers"
                )
            );
        }

        try {
            event = stripe!.webhooks.constructEvent(
                req.body,
                signature,
                endpointSecret
            );
        } catch (err) {
            logger.error(`Webhook signature verification failed.`, err);
            return next(
                createHttpError(
                    HttpCode.UNAUTHORIZED,
                    "Webhook signature verification failed"
                )
            );
        }
    }
    let subscription;
    let previousAttributes;
    // Handle the event
    switch (event.type) {
        case "customer.created":
            const customer = event.data.object;
            logger.info("Customer created: ", customer);
            handleCustomerCreated(customer);
            break;
        case "customer.updated":
            const customerUpdated = event.data.object;
            logger.info("Customer updated: ", customerUpdated);
            handleCustomerUpdated(customerUpdated);
            break;
        case "customer.deleted":
            const customerDeleted = event.data.object;
            logger.info("Customer deleted: ", customerDeleted);
            handleCustomerDeleted(customerDeleted);
            break;
        case "customer.subscription.paused":
            subscription = event.data.object;
            previousAttributes = event.data.previous_attributes;
            handleSubscriptionUpdated(subscription, previousAttributes);
            break;
        case "customer.subscription.resumed":
            subscription = event.data.object;
            previousAttributes = event.data.previous_attributes;
            handleSubscriptionUpdated(subscription, previousAttributes);
            break;
        case "customer.subscription.deleted":
            subscription = event.data.object;
            handleSubscriptionDeleted(subscription);
            break;
        case "customer.subscription.created":
            subscription = event.data.object;
            handleSubscriptionCreated(subscription);
            break;
        case "customer.subscription.updated":
            subscription = event.data.object;
            previousAttributes = event.data.previous_attributes;
            handleSubscriptionUpdated(subscription, previousAttributes);
            break;
        case "customer.subscription.trial_will_end":
            subscription = event.data.object;
            // Then define and call a method to handle the subscription trial ending.
            // handleSubscriptionTrialEnding(subscription);
            break;
        case "entitlements.active_entitlement_summary.updated":
            subscription = event.data.object;
            logger.info(
                `Active entitlement summary updated for ${subscription}.`
            );
            // Then define and call a method to handle active entitlement summary updated
            // handleEntitlementUpdated(subscription);
            break;
        default:
            // Unexpected event type
            logger.info(`Unhandled event type ${event.type}.`);
    }
    // Return a 200 response to acknowledge receipt of the event
    return response(res, {
        data: null,
        success: true,
        error: false,
        message: "Webhook event processed successfully",
        status: HttpCode.CREATED
    });
}
