import { Request, ResponseToolkit, ResponseObject } from "@hapi/hapi";
import { PlanService } from "../services/plan.service";
import { AppError } from "../../utils/errors";
import { PLAN } from "../config/constants";
import { Common } from "../../utils/common";

export class PlanHandler {
    private getPlanServiceObject = async (request: Request) => {
        let variables = await Common.getVariables(request);
        let userService = new PlanService(variables);
        return userService;
    };

    // Handles the creation of a new category type
    create = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let planService = await this.getPlanServiceObject(request);
            const payload = request.payload as PlanRequestObject;
            const createPlanInput: PlanCreateServiceInput = {
                name: payload.name,
                description: payload.description,
                status: payload.status,
                prices: payload.prices,
            };
            let plan: PlanObjectInteface = await planService.createPlan(createPlanInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: plan }).code(201);
        } catch (err) {
            if (err instanceof AppError) {
                throw err;
            }
            throw new AppError(500, "SOMETHING_WENT_WRONG_IN_SERVICE", err);
        }
    };

    // Handles the updation of a category type
    update = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let planService = await this.getPlanServiceObject(request);
            const payload = request.payload as PlanRequestObject;
            const params = request.params as PlanIdentifierObject;
            const updatePlanInput: PlanUpdateServiceInput = {
                id: params.id,
                name: payload.name,
                description: payload.description,
                status: payload.status,
                prices: payload.prices,
            };
            let plan: PlanObjectInteface = await planService.updatePlan(updatePlanInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: plan }).code(200);
        } catch (err) {
            if (err instanceof AppError) {
                throw err;
            }
            throw new AppError(500, "SOMETHING_WENT_WRONG_IN_SERVICE", err);
        }
    };

    // Handles the deletion of a category type
    delete = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let planService = await this.getPlanServiceObject(request);
            const params = request.params as PlanIdentifierObject;
            const deletePlanInput: PlanDeleteServiceInput = { id: params.id };
            let plan: PlanObjectInteface = await planService.deletePlan(deletePlanInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: plan }).code(200);
        } catch (err) {
            if (err instanceof AppError) {
                throw err;
            }
            throw new AppError(500, "SOMETHING_WENT_WRONG_IN_SERVICE", err);
        }
    };

    // get category type by id
    getById = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let planService = await this.getPlanServiceObject(request);
            const params = request.params as PlanIdentifierObject;
            const getByIdInput: PlanGetByIdServiceInput = { id: params.id };
            let plan: PlanObjectInteface = await planService.getById(getByIdInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: plan }).code(200);
        } catch (err) {
            if (err instanceof AppError) {
                throw err;
            }
            throw new AppError(500, "SOMETHING_WENT_WRONG_IN_SERVICE", err);
        }
    };

    // get category type by code
    getByCode = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let planService = await this.getPlanServiceObject(request);
            const params = request.params as PlanStringIdentifierObject;
            const getByCodeInput: PlanGetByCodeServiceInput = { code: params.code };
            let plan: PlanObjectInteface = await planService.getByCode(getByCodeInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: plan }).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
    list = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let planService = await this.getPlanServiceObject(request);
            let listRequest = request.query as PlanListRequestObject;
            const getPlansInput: PlanGetPlansServiceInput = { listRequest };
            let plans: PlanPaginatedList = await planService.getPlans(getPlansInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: plans }).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
    listPlan = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let planService = await this.getPlanServiceObject(request);
            let listRequest = request.query as PlanListRequestObject;
            listRequest.status = PLAN.STATUS.ACTIVE;
            const getPlansInput: PlanGetPlansServiceInput = { listRequest };
            let plans: PlanPaginatedList = await planService.getPlans(getPlansInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: plans }).code(200);
        } catch (err) {
            if (err instanceof AppError) {
                throw err;
            }
            throw new AppError(500, "SOMETHING_WENT_WRONG_IN_SERVICE", err);
        }
    };

    // listAll category types with filter
    listAll = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let planService = await this.getPlanServiceObject(request);
            let listRequest = request.query as PlanListAllRequestObject;
            const getAllPlansInput: PlanGetAllPlansServiceInput = { listRequest };
            let plans: PlanObjectSummaryInteface[] = await planService.getAllPlans(getAllPlansInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: plans }).code(200);
        } catch (err) {
            if (err instanceof AppError) {
                throw err;
            }
            throw new AppError(500, "SOMETHING_WENT_WRONG_IN_SERVICE", err);
        }
    };

    // list all revisions of category type
    listRevisions = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let planService = await this.getPlanServiceObject(request);
            let listRequest = request.query as PlanListRequestObject;
            const params = request.params as PlanIdentifierObject;
            const getPlansRevisionsInput: PlanGetPlansRevisionsServiceInput = { id: params.id, listRequest };
            let plans: PlanPaginatedList = await planService.getPlansRevisions(getPlansRevisionsInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: plans }).code(200);
        } catch (err) {
            if (err instanceof AppError) {
                throw err;
            }
            throw new AppError(500, "SOMETHING_WENT_WRONG_IN_SERVICE", err);
        }
    };

    // restore category type revision
    restoreRevision = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let planService = await this.getPlanServiceObject(request);
            const params = request.params as PlanIdentifierObject;
            const restoreRevisionInput: PlanRestoreRevisionServiceInput = { id: params.id };
            let plan: PlanObjectInteface = await planService.restoreRevision(restoreRevisionInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: plan }).code(200);
        } catch (err) {
            if (err instanceof AppError) {
                throw err;
            }
            throw new AppError(500, "SOMETHING_WENT_WRONG_IN_SERVICE", err);
        }
    };

    // set category type sort order
    setSortOrder = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let planService = await this.getPlanServiceObject(request);
            const params = request.params as PlanIdentifierObject;
            const payload = request.payload as PlanSortRequest;
            const setSortOrderInput: PlanSetSortOrderServiceInput = { id: params.id, before: payload.before, after: payload.after };
            let sortOrder = await planService.setSortOrder(setSortOrderInput);
            if (sortOrder) return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY" }).code(200);
            throw new AppError(400, "ERROR_WHILE_UPDATING_SORT_ORDER", {});
        } catch (err) {
            if (err instanceof AppError) {
                throw err;
            }
            throw new AppError(500, "SOMETHING_WENT_WRONG_IN_SERVICE", err);
        }
    };

    // update plan status
    updateStatus = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let planService = await this.getPlanServiceObject(request);
            const params = request.params as PlanIdentifierObject;
            const payload = request.payload as PlanStatusObject;
            const updateStatusInput: PlanUpdateStatusServiceInput = { id: params.id, status: payload.status };
            let plan = await planService.updateStatus(updateStatusInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: plan }).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 price for the stripe product
    createPrice = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let planService = await this.getPlanServiceObject(request);
            const params = request.params as PlanIdentifierObject;
            const payload = request.payload as PriceInterface;
            const createPriceInput: PlanCreatePriceServiceInput = {
                amount: payload.amount,
                duration: payload.duration,
                frequency: payload.frequency,
                autoRenew: payload.autoRenew,
                currency: payload.currency,
                planId: params.id,
            };
            let updatedPlan = await planService.createPrice(createPriceInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: updatedPlan }).code(201);
        } catch (err) {
            if (err instanceof AppError) {
                throw err;
            }
            throw new AppError(500, "SOMETHING_WENT_WRONG_IN_SERVICE", err);
        }
    };

    // update plan status
    updatePriceStatus = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let planService = await this.getPlanServiceObject(request);
            const params = request.params as any;
            const payload = request.payload as PlanStatusObject;
            const updatePriceStatusInput: PlanUpdatePriceStatusServiceInput = {
                id: +params.priceId,
                planId: +params.id,
                status: payload.status,
            };
            let plan = await planService.updatePriceStatus(updatePriceStatusInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: plan }).code(200);
        } catch (err) {
            if (err instanceof AppError) {
                throw err;
            }
            throw new AppError(500, "SOMETHING_WENT_WRONG_IN_SERVICE", err);
        }
    };
}
