import { Request, ResponseToolkit, ResponseObject } from '@hapi/hapi';
import { PaymentService } from "../services/payment.service";
import { AppError } from "../../utils/errors";
import { WhereOperators } from 'sequelize';
import { PLAN } from "../config/constants"
import { Common } from '../../utils/common';

export class PaymentHandler {
    // set the class variables
    // private getPaymentServiceObject = (request: Request) => {
    //     const scope = (request.auth?.isAuthenticated && request.auth.credentials.scope) ? request.auth.credentials.scope : null;
    //     const userId = request.auth?.isAuthenticated ? (request.auth.credentials as unknown as AuthData).userData.userId : null;
    //     const accountId = request.auth?.isAuthenticated ? (request.auth.credentials as unknown as AuthData).userData.accountId : null;
    //     const language: string = (request.headers?.language || process.env.DEFAULT_LANGUAGE_CODE || 'en') as string;
    //     let planService = new PaymentService({ userId: userId, accountId: accountId, language: language, scope: scope });
    //     return planService;
    // }

    private getPaymentServiceObject = async (request: Request) => {
        let variables = await Common.getVariables(request)
        let userService = new PaymentService(variables);
        return userService;
    }

    // Handles the creation of a new category type
    buySubscription = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let paymentService = await this.getPaymentServiceObject(request);
            const { planId, priceId } = request.payload as SubscriptionRequestObject;

            const buySubscriptionInput: PaymentBuySubscriptionServiceInput = { planId, priceId };
            let subscription = await paymentService.buySubscription(buySubscriptionInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: subscription }).code(201);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    // Handles the creation of a new category type
    updateSubscription = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let paymentService = await this.getPaymentServiceObject(request);
            const { planId, priceId } = request.payload as SubscriptionRequestObject;

            const updateSubscriptionInput: PaymentUpdateSubscriptionServiceInput = { planId, priceId };
            let subscription = await paymentService.updateSubscription(updateSubscriptionInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: subscription }).code(201);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    // Handles the creation of a new category type
    cancelSubscription = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let paymentService = await this.getPaymentServiceObject(request);

            const cancelSubscriptionInput: PaymentCancelSubscriptionServiceInput = { id: request.params.id };
            let subscription = await paymentService.cancelSubscription(cancelSubscriptionInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: subscription }).code(201);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    // list category types with filter
    listSubscriptions = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let forUser = true;
            let paymentService = await this.getPaymentServiceObject(request);
            let listRequest = request.query as SubscriptionListRequestObject;
            const getSubscriptionsInput: PaymentGetSubscriptionsServiceInput = { listRequest, forUser };
            let subscriptions: SubscriptionPaginatedList = await paymentService.getSubscriptions(getSubscriptionsInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: subscriptions }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    // list category types with filter
    listUserSubscriptions = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let forUser = false;
            let paymentService = await this.getPaymentServiceObject(request);
            let listRequest = request.query as SubscriptionListRequestObject;
            const getSubscriptionsInput: PaymentGetSubscriptionsServiceInput = { listRequest, forUser };
            let subscriptions: SubscriptionPaginatedList = await paymentService.getSubscriptions(getSubscriptionsInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: subscriptions }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    getSubscriptionById = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let paymentService = await this.getPaymentServiceObject(request);
            let id = request.params.id;
            const getSubscriptionByIdInput: PaymentGetSubscriptionByIdServiceInput = { id };
            let subscriptions: SubscriptionInterface = await paymentService.getSubscriptionById(getSubscriptionByIdInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: subscriptions }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    // list category types with filter
    listTranasctions = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let forUser = true;
            let paymentService = await this.getPaymentServiceObject(request);
            let listRequest = request.query as TranasctionListRequestObject;
            const getTransactionsInput: PaymentGetTransactionsServiceInput = { listRequest, forUser };
            let transactions: TranasctionPaginatedList = await paymentService.getTransactions(getTransactionsInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: transactions }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    // list category types with filter
    listUserTranasctions = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let forUser = false;
            let paymentService = await this.getPaymentServiceObject(request);
            let listRequest = request.query as TranasctionListRequestObject;
            const getTransactionsInput: PaymentGetTransactionsServiceInput = { listRequest, forUser };
            let transactions: TranasctionPaginatedList = await paymentService.getTransactions(getTransactionsInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: transactions }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }


    // Handles the creation of a new category type
    initiatePayment = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let paymentService = await this.getPaymentServiceObject(request);
            let email = (request.auth.credentials as unknown as AuthData).userData.email;

            const { planId, priceId } = request.payload as SubscriptionRequestObject;

            const initiatePaymentInput: PaymentInitiatePaymentServiceInput = { email, planId, priceId };
            let subscription = await paymentService.initiatePayment(initiatePaymentInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: subscription }).code(201);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    updatePayment = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let paymentService = await this.getPaymentServiceObject(request);

            const { planId, priceId } = request.payload as SubscriptionRequestObject;

            const updatePaymentInput: PaymentUpdatePaymentServiceInput = { planId, priceId };
            let subscription = await paymentService.updatePayment(updatePaymentInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: subscription }).code(201);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    // Handles the creation of a new category type
    initiateRefund = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let paymentService = await this.getPaymentServiceObject(request);
            const { transactionId, amount } = request.payload as {transactionId: number, amount: number};

            const initiateRefundInput: PaymentInitiateRefundServiceInput = { transactionId, amount };
            let subscription = await paymentService.initiateRefund(initiateRefundInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: subscription }).code(201);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    fetchStatus = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let paymentService = await this.getPaymentServiceObject(request);
            let merchantOrderId = request.params.merchantOrderId;
            const fetchStatusInput: PaymentFetchStatusServiceInput = { merchantOrderId };
            let status = await paymentService.fetchStatus(fetchStatusInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: status }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }


    subscriptionWebhook = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let paymentService = await this.getPaymentServiceObject(request);
            // const sig = request.headers["stripe-signature"];
            // if (!sig) {
            //     throw new AppError(400, 'Missing Stripe signature', {});
            // };
            // event = stripe.webhooks.constructEvent(request.payload, sig, process.env.STRIPE_WEBHOOK_SECRET!);

            const event = request.payload;
            const subscriptionWebhookInput: PaymentWebhookServiceInput = { data: event };
            let giftCard = await paymentService.subscriptionWebhook(subscriptionWebhookInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: giftCard }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    paymentWebhook = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let paymentService = await this.getPaymentServiceObject(request);
            if(request.query.mode !== process.env.PAYMENT_WEBHOOK_MODE) {
                return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: {} }).code(200);
            }
            const event = request.payload;
            const paymentWebhookInput: PaymentWebhookServiceInput = { data: event };
            let giftCard = await paymentService.paymentWebhook(paymentWebhookInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: giftCard }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    getWalletIntent = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let paymentService = await this.getPaymentServiceObject(request);
            const { amount, currency } = request.payload as ClientSecretRequest;
            const createWalletIntentInput: PaymentCreateWalletIntentServiceInput = { amount, currency };
            let clientSecret = await paymentService.createWalletIntent(createWalletIntentInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: clientSecret }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    attachPaymentMethod = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let paymentService = await this.getPaymentServiceObject(request);
            const paymentMethodId = (request.payload as {paymentMethodId: string}).paymentMethodId;
            const email = (request.payload as {email: string}).email;
            const attachPaymentMethodInput: PaymentAttachPaymentMethodServiceInput = { paymentMethodId, email };
            let paymentMethods = await paymentService.attachPaymentMethod(attachPaymentMethodInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: paymentMethods }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    removePaymentMethod = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let paymentService = await this.getPaymentServiceObject(request);
            const paymentMethodId = (request.payload as {paymentMethodId: string}).paymentMethodId;
            const removePaymentMethodInput: PaymentMethodIdentifierServiceInput = { paymentMethodId };
            let paymentMethods = await paymentService.removePaymentMethod(removePaymentMethodInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: paymentMethods }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    changeDefaultPaymentMethod = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let paymentService = await this.getPaymentServiceObject(request);
            const paymentMethodId = (request.payload as {paymentMethodId: string}).paymentMethodId;
            const defaultPaymentMethodInput: PaymentMethodIdentifierServiceInput = { paymentMethodId };
            let paymentMethods = await paymentService.changeDefaultPaymentMethod(defaultPaymentMethodInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: paymentMethods }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    listPaymentMethods = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let paymentService = await this.getPaymentServiceObject(request);
            let paymentMethods = await paymentService.listPaymentMethods({});
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: paymentMethods }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    revenueStats = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let paymentService = await this.getPaymentServiceObject(request);
            const query = request.query;
            const revenueStatsInput: PaymentRevenueStatsServiceInput = { startDate: query.startDate, endDate: query.endDate };
            let paymentMethods = await paymentService.revenueStats(revenueStatsInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: paymentMethods }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    subscriptionStats = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let paymentService = await this.getPaymentServiceObject(request);
            const query = request.query;
            const subscriptionStatsInput: PaymentSubscriptionStatsServiceInput = { startDate: query.startDate, endDate: query.endDate };
            let paymentMethods = await paymentService.subscriptionStats(subscriptionStatsInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: paymentMethods }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    subscriptionUserStats = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let paymentService = await this.getPaymentServiceObject(request);
            const query = request.query;
            const subscriptionUserStatsInput: PaymentSubscriptionUserStatsServiceInput = { startDate: query.startDate, endDate: query.endDate };
            let paymentMethods = await paymentService.subscriptionUserStats(subscriptionUserStatsInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: paymentMethods }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    verifyAppPurchase = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let paymentService = await this.getPaymentServiceObject(request);
            const { platform, planId, priceId, receipt, purchaseData } = request.payload as AppPurchaseVerifyRequestObject;
            const verifyAppPurchaseInput: PaymentVerifyAppPurchaseServiceInput = {
                platform, planId, priceId, receipt, purchaseData
            };
            let verifyPurchase = await paymentService.verifyAppPurchase(verifyAppPurchaseInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: verifyPurchase }).code(201);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    verifyPayment = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let paymentService = await this.getPaymentServiceObject(request);
            const payload = request.payload as { razorpayPaymentId: string, razorpayOrderId?: string, razorpaySubscriptionId?: string, razorpaySignature: string };
            const verifyPaymentInput: any = payload; // Can strongly type this later if needed
            let verifyPurchase = await paymentService.verifyPayment(verifyPaymentInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: verifyPurchase }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }
}
