import { Request, ResponseToolkit, ResponseObject } from '@hapi/hapi';
import { PostService } from "../services/post.service";
import { AppError } from "../../utils/errors";
import { Common } from "../../utils/common"

export class PostHandler {
    // set the class variables
    private getPostServiceObject = async (request: Request) => {
        let variables = await Common.getVariables(request);
        let postService = new PostService(variables);
        return postService;
    }

    // Handles the creation of a new post content
    create = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let postService = await this.getPostServiceObject(request);
            const createPostRequest = request.payload as PostRequestObject;
            const authorId = createPostRequest.authorId || (request.auth.credentials as any).userData.userId;
            const createPostServiceInput: PostCreateServiceInput = {
                postType: createPostRequest.postType,
                authorId: authorId,
                categoryIds: createPostRequest.categoryIds,
                title: createPostRequest.title,
                description: createPostRequest.description,
                limitedContent: createPostRequest.limitedContent,
                exerpt: createPostRequest.exerpt,
                isFeatured: createPostRequest.isFeatured,
                status: createPostRequest.status,
                visibility: createPostRequest.visibility,
                isExclusive: createPostRequest.isExclusive,
                publishedAt: createPostRequest.publishedAt,
                postAttachmentIds: createPostRequest.postAttachmentIds,
                featuredImageId: createPostRequest.featuredImageId,
                tags: createPostRequest.tags,
                metaTitle: createPostRequest.metaTitle,
                metaDescription: createPostRequest.metaDescription,
                metaKeywords: createPostRequest.metaKeywords,
                canonicalUrl: createPostRequest.canonicalUrl
            };
            let post: PostObjectInteface = await postService.createPost(createPostServiceInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: post }).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 post content
    update = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let postService = await this.getPostServiceObject(request);
            const updatePostRequest = request.payload as PostRequestObject;
            const { id } = request.params as PostIdentifierObject;
            const authorId = updatePostRequest.authorId || (request.auth.credentials as any).userData.userId;
            const updatePostServiceInput: PostUpdateServiceInput = {
                id: id,
                authorId: authorId,
                postType: updatePostRequest.postType,
                categoryIds: updatePostRequest.categoryIds,
                title: updatePostRequest.title,
                description: updatePostRequest.description,
                limitedContent: updatePostRequest.limitedContent,
                exerpt: updatePostRequest.exerpt,
                isFeatured: updatePostRequest.isFeatured,
                status: updatePostRequest.status,
                visibility: updatePostRequest.visibility,
                isExclusive: updatePostRequest.isExclusive,
                publishedAt: updatePostRequest.publishedAt,
                postAttachmentIds: updatePostRequest.postAttachmentIds,
                featuredImageId: updatePostRequest.featuredImageId,
                tags: updatePostRequest.tags,
                metaTitle: updatePostRequest.metaTitle,
                metaDescription: updatePostRequest.metaDescription,
                metaKeywords: updatePostRequest.metaKeywords,
                canonicalUrl: updatePostRequest.canonicalUrl
            };
            let post: PostObjectInteface = await postService.updatePost(updatePostServiceInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: post }).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 post content
    delete = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let postService = await this.getPostServiceObject(request);
            const { id, postType } = request.params as PostIdentifierObject;
            const deletePostServiceInput: PostDeleteServiceInput = { id, postType };
            let post: PostObjectInteface = await postService.deletePost(deletePostServiceInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: post }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    // get post content by id
    getById = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let postService = await this.getPostServiceObject(request);
            const { id, postType } = request.params as PostIdentifierObject;
            const getByIdServiceInput: PostGetByIdServiceInput = { id, postType };
            let post: PostObjectInteface = await postService.getById(getByIdServiceInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: post }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    // get post content by id
    publicGetById = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let postService = await this.getPostServiceObject(request);
            const { id, postType } = request.params as PostIdentifierObject;
            const publicGetByIdServiceInput: PostPublicGetByIdServiceInput = { id, postType };
            let post: PostObjectSummaryInteface = await postService.publicGetById(publicGetByIdServiceInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: post }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    // get post content by code
    getByCode = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let postService = await this.getPostServiceObject(request);
            const { code, postType } = request.params as PostStringIdentifierObject;
            const getByCodeServiceInput: PostGetByCodeServiceInput = { code, postType };
            let post: PostObjectInteface = await postService.getByCode(getByCodeServiceInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: post }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    // list post content with filter
    list = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let postService = await this.getPostServiceObject(request);
            let listRequest = request.query as PostListRequestObject;
            let { postType } = request.params as PostTypeIdentifierObject;
            const getPostServiceInput: PostGetPostsServiceInput = { postType, listRequest };
            let post: PostPaginatedList = await postService.getPost(getPostServiceInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: post }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    //list post content with filter
    listByTags = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let postService = await this.getPostServiceObject(request);
            let listRequest = request.query as PostListRequestObject;
            const getPostByTagsServiceInput: PostGetPostsByTagsServiceInput = { listRequest };
            let post: PostPaginatedList = await postService.getPostByTags(getPostByTagsServiceInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: post }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    // list All post content with filter
    listAll = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let postService = await this.getPostServiceObject(request);
            let listRequest = request.query as PostListAllRequestObject;
            let { postType } = request.params as PostTypeIdentifierObject;
            const getAllPostServiceInput: PostGetAllPostsServiceInput = { postType, listRequest };
            let post: PostObjectSummaryInteface[] = await postService.getAllPost(getAllPostServiceInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: post }).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 post content
    listRevisions = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let postService = await this.getPostServiceObject(request);
            let listRequest = request.query as PostListRequestObject;
            let { id, postType } = request.params as PostIdentifierObject;
            const getPostRevisionsServiceInput: PostGetPostRevisionsServiceInput = { id, postType, listRequest };
            let post: PostPaginatedList = await postService.getPostRevisions(getPostRevisionsServiceInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: post }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    // restore post content revision
    restoreRevision = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let postService = await this.getPostServiceObject(request);
            const { id, postType } = request.params as PostIdentifierObject;
            const restoreRevisionServiceInput: PostRestoreRevisionServiceInput = { id, postType };
            let post: PostObjectInteface = await postService.restoreRevision(restoreRevisionServiceInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: post }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    // set post content sort order
    setSortOrder = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let postService = await this.getPostServiceObject(request);
            const { id, postType } = request.params as PostIdentifierObject;
            const { before, after } = request.payload as PostSortRequest;
            const setSortOrderServiceInput: PostSetSortOrderServiceInput = { id, postType, before, after };
            let sortOrder = await postService.setSortOrder(setSortOrderServiceInput);
            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 post content status
    updateStatus = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let postService = await this.getPostServiceObject(request);
            const { id, postType } = request.params as PostIdentifierObject;
            const { status } = request.payload as PostStatusObject;
            const updateStatusServiceInput: PostUpdateStatusServiceInput = { id, postType, status };
            let post = await postService.updateStatus(updateStatusServiceInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: post }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }
    getPublicPostByCode = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let postService = await this.getPostServiceObject(request);
            const { code } = request.params as PostStringIdentifierObject;
            const getPublicPostByCodeServiceInput: PostGetPublicPostByCodeServiceInput = { code };
            let post: PostObjectSummaryInteface = await postService.getPublicPostByCode(getPublicPostByCodeServiceInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: post }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    getPublicPageByCode = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            const { code } = request.params;
            let postService = await this.getPostServiceObject(request);
            const getPublicPageByCodeServiceInput: PostGetPublicPostByCodeServiceInput = { code };
            let post: PostObjectSummaryInteface = await postService.getPublicPageByCode(getPublicPageByCodeServiceInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: post }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    listPublicPages = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let postService = await this.getPostServiceObject(request);
            const listRequest = request.query as PostListPublicRequestObject;
            // Force postType to page
            listRequest.postType = 'page';
            
            // Default sorting for public pages list
            if (!listRequest.sortBy) {
                listRequest.sortBy = 'id';
                listRequest.sortDirection = 'asc';
            }
            
            const getPublicPostListServiceInput: PostGetPublicPostListServiceInput = { listRequest };
            let posts: PostPaginatedList = await postService.getPublicPageList(getPublicPostListServiceInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: posts }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    // list all published posts publicly (no auth)
    publicList = async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
        try {
            let postService = await this.getPostServiceObject(request);
            const { postType } = request.params as PostTypeIdentifierObject;
            let listRequest = { ...(request.query as PostListPublicRequestObject), postType: postType || null };
            const getPublicPostListServiceInput: PostGetPublicPostListServiceInput = { listRequest };
            let posts: PostPaginatedList = await postService.getPublicPostList(getPublicPostListServiceInput);
            return h.response({ message: "REQUEST_PROCESSED_SUCCESSFULLY", responseData: posts }).code(200);
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }
}
