import { Request, ResponseToolkit, ResponseObject } from "@hapi/hapi";
import { CategoryService } from "../services/category.service";
import { AppError } from "../../utils/errors";
import { CATEGORY } from "../config/constants";
import { Common } from "../../utils/common";

export class CategoryHandler {
  // set the class variables
  private getCategoryServiceObject = async (request: Request) => {
    let variables = await Common.getVariables(request);
    let categoryService = new CategoryService(variables);
    return categoryService;
  };

  // Handles the creation of a new category
  create = async (
    request: Request,
    h: ResponseToolkit,
  ): Promise<ResponseObject> => {
    try {
      let categoryService = await this.getCategoryServiceObject(request);
      const {
        name,
        description,
        categoryTypeCode,
        imageId,
        parentId,
        status,
        refLink,
        seaQAApplicability
      } = request.payload as CategoryRequestObject;
      const createCategoryInput: CategoryCreateServiceInput = {
        name,
        description,
        categoryTypeCode,
        imageId,
        parentId,
        status,
        refLink,
        seaQAApplicability
      };

      let category: CategoryObjectInteface =
        await categoryService.createCategory(createCategoryInput);
      return h
        .response({
          message: "REQUEST_PROCESSED_SUCCESSFULLY",
          responseData: category,
        })
        .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
  update = async (
    request: Request,
    h: ResponseToolkit,
  ): Promise<ResponseObject> => {
    try {
      let categoryService = await this.getCategoryServiceObject(request);
      const {
        name,
        description,
        categoryTypeCode,
        imageId,
        parentId,
        status,
        refLink,
        seaQAApplicability
      } = request.payload as CategoryRequestObject;
      const { id } = request.params as CategoryIdentifierObject;
      const updateCategoryInput: CategoryUpdateServiceInput = {
        id,
        name,
        description,
        categoryTypeCode,
        imageId,
        parentId,
        status,
        refLink,
        seaQAApplicability
      };

      let category: CategoryObjectInteface =
        await categoryService.updateCategory(updateCategoryInput);
      return h
        .response({
          message: "REQUEST_PROCESSED_SUCCESSFULLY",
          responseData: category,
        })
        .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
  delete = async (
    request: Request,
    h: ResponseToolkit,
  ): Promise<ResponseObject> => {
    try {
      let categoryService = await this.getCategoryServiceObject(request);
      const { id } = request.params as CategoryIdentifierObject;
      const { categoryTypeCode } =
        request.params as CategoryTypeCodeIdentifierObject;
      const deleteCategoryInput: CategoryDeleteServiceInput = {
        id,
        categoryTypeCode,
      };
      let category: CategoryObjectInteface =
        await categoryService.deleteCategory(deleteCategoryInput);
      return h
        .response({
          message: "REQUEST_PROCESSED_SUCCESSFULLY",
          responseData: category,
        })
        .code(200);
    } catch (err) {
      if (err instanceof AppError) {
        throw err;
      }
      throw new AppError(500, "SOMETHING_WENT_WRONG_IN_SERVICE", err);
    }
  };

  // get category by id
  getById = async (
    request: Request,
    h: ResponseToolkit,
  ): Promise<ResponseObject> => {
    try {
      let categoryService = await this.getCategoryServiceObject(request);
      const { id } = request.params as CategoryIdentifierObject;
      const getCategoryByIdInput: CategoryGetByIdServiceInput = { id };
      let category: CategoryObjectInteface =
        await categoryService.getById(getCategoryByIdInput);
      return h
        .response({
          message: "REQUEST_PROCESSED_SUCCESSFULLY",
          responseData: category,
        })
        .code(200);
    } catch (err) {
      if (err instanceof AppError) {
        throw err;
      }
      throw new AppError(500, "SOMETHING_WENT_WRONG_IN_SERVICE", err);
    }
  };

  // get category by code
  getByCode = async (
    request: Request,
    h: ResponseToolkit,
  ): Promise<ResponseObject> => {
    try {
      let categoryService = await this.getCategoryServiceObject(request);
      const { code } = request.params as CategoryStringIdentifierObject;
      const getCategoryByCodeInput: CategoryGetByCodeServiceInput = { code };
      let category: CategoryObjectInteface = await categoryService.getByCode(
        getCategoryByCodeInput,
      );
      return h
        .response({
          message: "REQUEST_PROCESSED_SUCCESSFULLY",
          responseData: category,
        })
        .code(200);
    } catch (err) {
      if (err instanceof AppError) {
        throw err;
      }
      throw new AppError(500, "SOMETHING_WENT_WRONG_IN_SERVICE", err);
    }
  };

  // list categories with filter
  list = async (
    request: Request,
    h: ResponseToolkit,
  ): Promise<ResponseObject> => {
    try {
      let categoryService = await this.getCategoryServiceObject(request);
      let listRequest = request.query as CategoryListRequestObject;
      let { categoryTypeCode } =
        request.params as CategoryTypeCodeIdentifierObject;
      const getCategoriesInput: CategoryGetCategoriesServiceInput = {
        categoryTypeCode,
        listRequest,
      };
      let categories: CategoryPaginatedList =
        await categoryService.getCategories(getCategoriesInput);
      return h
        .response({
          message: "REQUEST_PROCESSED_SUCCESSFULLY",
          responseData: categories,
        })
        .code(200);
    } catch (err) {
      if (err instanceof AppError) {
        throw err;
      }
      throw new AppError(500, "SOMETHING_WENT_WRONG_IN_SERVICE", err);
    }
  };

  // list categories with filter
  categories = async (
    request: Request,
    h: ResponseToolkit,
  ): Promise<ResponseObject> => {
    try {
      let categoryService = await this.getCategoryServiceObject(request);
      let listRequest = request.query as CategoryListRequestObject;
      let { categoryTypeCode } =
        request.params as CategoryTypeCodeIdentifierObject;
      listRequest.status = CATEGORY.STATUS.ACTIVE;
      const getCategoriesInput: CategoryGetCategoriesServiceInput = {
        categoryTypeCode,
        listRequest,
      };
      let categoriesList: CategoryPaginatedList =
        await categoryService.getCategories(getCategoriesInput);
      return h
        .response({
          message: "REQUEST_PROCESSED_SUCCESSFULLY",
          responseData: categoriesList,
        })
        .code(200);
    } catch (err) {
      if (err instanceof AppError) {
        throw err;
      }
      throw new AppError(500, "SOMETHING_WENT_WRONG_IN_SERVICE", err);
    }
  };

  // list All categories with filter
  listAll = async (
    request: Request,
    h: ResponseToolkit,
  ): Promise<ResponseObject> => {
    try {
      let categoryService = await this.getCategoryServiceObject(request);
      let { categoryTypeCode } =
        request.params as CategoryTypeCodeIdentifierObject;
      let listRequest = request.query as CategoryListAllRequestObject;
      const getAllCategoriesInput: CategoryGetAllCategoriesServiceInput = {
        categoryTypeCode,
        listRequest,
      };
      let categoryTypes: CategoryObjectSummaryInteface[] =
        await categoryService.getAllCategories(getAllCategoriesInput);
      return h
        .response({
          message: "REQUEST_PROCESSED_SUCCESSFULLY",
          responseData: categoryTypes,
        })
        .code(200);
    } catch (err) {
      if (err instanceof AppError) {
        throw err;
      }
      throw new AppError(500, "SOMETHING_WENT_WRONG_IN_SERVICE", err);
    }
  };
  // list All categories with filter
  listAllActive = async (
    request: Request,
    h: ResponseToolkit,
  ): Promise<ResponseObject> => {
    try {
      let categoryService = await this.getCategoryServiceObject(request);
      let { categoryTypeCode } =
        request.params as CategoryTypeCodeIdentifierObject;
      let listRequest = request.query as CategoryListAllRequestObject;
      listRequest.status = CATEGORY.STATUS.ACTIVE;
      const getAllCategoriesInput: CategoryGetAllCategoriesServiceInput = {
        categoryTypeCode,
        listRequest,
      };
      let categoryTypes: CategoryObjectSummaryInteface[] =
        await categoryService.getAllCategories(getAllCategoriesInput);
      return h
        .response({
          message: "REQUEST_PROCESSED_SUCCESSFULLY",
          responseData: categoryTypes,
        })
        .code(200);
    } catch (err) {
      console.log(err);
      if (err instanceof AppError) {
        throw err;
      }
      throw new AppError(500, "SOMETHING_WENT_WRONG_IN_SERVICE", err);
    }
  };

  // list All categories with filter
  listAllTags = async (
    request: Request,
    h: ResponseToolkit,
  ): Promise<ResponseObject> => {
    try {
      let categoryService = await this.getCategoryServiceObject(request);
      const categoryTypeCode = "tag";
      let listRequest = request.query as CategoryListAllRequestObject;
      listRequest.status = CATEGORY.STATUS.ACTIVE;
      listRequest.parentId = null;
      const getAllCategoriesInput: CategoryGetAllCategoriesServiceInput = {
        categoryTypeCode,
        listRequest,
      };
      let categoryTypes: CategoryObjectSummaryInteface[] =
        await categoryService.getAllCategories(getAllCategoriesInput);
      return h
        .response({
          message: "REQUEST_PROCESSED_SUCCESSFULLY",
          responseData: categoryTypes,
        })
        .code(200);
    } catch (err) {
      if (err instanceof AppError) {
        throw err;
      }
      throw new AppError(500, "SOMETHING_WENT_WRONG_IN_SERVICE", err);
    }
  };

  // list all revisions of the category
  listRevisions = async (
    request: Request,
    h: ResponseToolkit,
  ): Promise<ResponseObject> => {
    try {
      let categoryService = await this.getCategoryServiceObject(request);
      let listRequest = request.query as CategoryListRequestObject;
      let { id } = request.params as CategoryIdentifierObject;
      const getCategoryRevisionsInput: CategoryGetCategoryRevisionsServiceInput =
        { id, listRequest };
      let categories: CategoryPaginatedList =
        await categoryService.getCategoryRevisions(getCategoryRevisionsInput);
      return h
        .response({
          message: "REQUEST_PROCESSED_SUCCESSFULLY",
          responseData: categories,
        })
        .code(200);
    } catch (err) {
      if (err instanceof AppError) {
        throw err;
      }
      throw new AppError(500, "SOMETHING_WENT_WRONG_IN_SERVICE", err);
    }
  };

  // restore category revision
  restoreRevision = async (
    request: Request,
    h: ResponseToolkit,
  ): Promise<ResponseObject> => {
    try {
      let categoryService = await this.getCategoryServiceObject(request);
      const { id } = request.params as CategoryIdentifierObject;
      const restoreCategoryRevisionInput: CategoryRestoreRevisionServiceInput =
        { id };
      let category: CategoryObjectInteface =
        await categoryService.restoreRevision(restoreCategoryRevisionInput);
      return h
        .response({
          message: "REQUEST_PROCESSED_SUCCESSFULLY",
          responseData: category,
        })
        .code(200);
    } catch (err) {
      if (err instanceof AppError) {
        throw err;
      }
      throw new AppError(500, "SOMETHING_WENT_WRONG_IN_SERVICE", err);
    }
  };

  // get category tree
  getCategoryTree = async (
    request: Request,
    h: ResponseToolkit,
  ): Promise<ResponseObject> => {
    try {
      let categoryService = await this.getCategoryServiceObject(request);
      const { categoryTypeCode } =
        request.params as CategoryTypeCodeIdentifierObject;
      const { code } = request.params as CategoryStringIdentifierObject;
      const getCategoryTreeInput: CategoryGetCategoryTreeServiceInput = {
        categoryTypeCode,
        code,
      };
      let categoryTree: CategoryTree[] =
        await categoryService.getCategoryTree(getCategoryTreeInput);
      return h
        .response({
          message: "REQUEST_PROCESSED_SUCCESSFULLY",
          responseData: categoryTree,
        })
        .code(200);
    } catch (err) {
      if (err instanceof AppError) {
        throw err;
      }
      throw new AppError(500, "SOMETHING_WENT_WRONG_IN_SERVICE", err);
    }
  };

  // set category sort order
  setSortOrder = async (
    request: Request,
    h: ResponseToolkit,
  ): Promise<ResponseObject> => {
    try {
      let categoryService = await this.getCategoryServiceObject(request);
      const { id, categoryTypeCode } =
        request.params as CategorySortIdentifierObject;
      const { before, after } = request.payload as CategorySortRequest;
      const setSortOrderInput: CategorySetSortOrderServiceInput = {
        id,
        categoryTypeCode,
        before,
        after,
      };
      let sortOrder = await categoryService.setSortOrder(setSortOrderInput);
      if (sortOrder)
        return h
          .response({ message: "REQUEST_PROCESSED_SUCCESSFULLY" })
          .code(200);
      else {
        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 category status
  updateStatus = async (
    request: Request,
    h: ResponseToolkit,
  ): Promise<ResponseObject> => {
    try {
      let categoryService = await this.getCategoryServiceObject(request);
      const { id } = request.params as CategoryIdentifierObject;
      const { status } = request.payload as CategoryStatusObject;
      const updateCategoryStatusInput: CategoryUpdateStatusServiceInput = {
        id,
        status,
      };
      let category = await categoryService.updateStatus(
        updateCategoryStatusInput,
      );
      return h
        .response({
          message: "REQUEST_PROCESSED_SUCCESSFULLY",
          responseData: category,
        })
        .code(200);
    } catch (err) {
      if (err instanceof AppError) {
        throw err;
      }
      throw new AppError(500, "SOMETHING_WENT_WRONG_IN_SERVICE", err);
    }
  };
}
