import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { useQuery } from '@apollo/client';
// I need to import the component with HOC withListener
// eslint-disable-next-line import/no-named-as-default
import ProductReviewsComponent, { INITIAL_PAGE_SIZE } from './ProductReviews';
import { PRODUCT_REVIEWS, PRODUCT_REVIEWS_STATS } from './graphql/query';
import withGraphQL from '../withGraphQL';
import { sortingParams } from './const';

const defaultProductReviewData = {
    totalCustomerReviews: 0,
    averageRating: 0,
    ratings: [],
    items: [],
    pageInfo: {
        endCursor: '0',
        hasNextPage: false
    },
    addReviewUrl: '',
    i18n: {
        labels: {}
    },
    fetchMore: () => {},
    setPaginatedData: () => {},
    refetch: () => {}
};

export const buildRatingsArray = ratingsBreakdown => {
    const ratingsArray = [{
        rating: 1,
        count: 0
    }, {
        rating: 2,
        count: 0
    }, {
        rating: 3,
        count: 0
    }, {
        rating: 4,
        count: 0
    }, {
        rating: 5,
        count: 0
    }];

    if (!ratingsBreakdown || !ratingsBreakdown.length) {
        return ratingsArray;
    }

    ratingsBreakdown.forEach(rating => {
        const index = parseInt(rating.rating, 10) - 1;
        const ratingNumber = ratingsArray[index];
        if (ratingNumber) {
            ratingsArray[index].count = rating.count;
        }
    });

    return ratingsArray;
};

export const mapComponentData = (
    { reviews: { nodes, pageInfo: { endCursor = '0', hasNextPage = false }, totalCount } },
    { addReviewUrl, i18n },
    fetchMore,
    setPaginatedData,
    refetch
) => ({
    items: nodes,
    addReviewUrl,
    pageInfo: {
        endCursor,
        hasNextPage
    },
    totalCount,
    i18n,
    fetchMore,
    setPaginatedData,
    refetch
});

export const ProductReviewsAdapter = ({ id, data, settings }) => {
    const defaultFetchPolicy = 'network-only';

    const {
        data: queryReviewData,
        loading: queryReviewLoading,
        error: queryReviewError,
        fetchMore,
        refetch
    } = useQuery(
        PRODUCT_REVIEWS,
        {
            variables: {
                productId: data.productId,
                first: INITIAL_PAGE_SIZE,
                orderByField: sortingParams.LATEST.orderByField,
                orderByDirection: sortingParams.LATEST.orderByDirection
            },
            fetchPolicy: defaultFetchPolicy
        }
    );

    const {
        data: queryReviewStatsData,
        loading: queryReviewStatsLoading,
        error: queryReviewStatsError
    } = useQuery(
        PRODUCT_REVIEWS_STATS,
        {
            variables: {
                productId: data.productId
            },
            fetchPolicy: defaultFetchPolicy
        }
    );

    const [productReviewsData, setProductReviewsData] = useState(defaultProductReviewData);
    const [productReviewsPaginatedData, setProductReviewsPaginatedData] = useState({});

    const hasQueryData = (error, loading, queryData) => (
        !error && !loading && queryData
    );

    useEffect(() => {
        const { addReviewUrl, i18n, isLoggedIn } = data;
        setProductReviewsData({
            ...productReviewsData,
            addReviewUrl,
            i18n,
            isLoggedIn
        });
    }, [data]);

    // PRODUCT_REVIEWS query
    useEffect(() => {
        if (hasQueryData(queryReviewError, queryReviewLoading, queryReviewData)) {
            const updatedData = mapComponentData(
                queryReviewData, data, fetchMore, setProductReviewsPaginatedData, refetch
            );
            setProductReviewsData({
                ...productReviewsData,
                ...updatedData
            });
        }
    }, [queryReviewData, queryReviewError, queryReviewLoading]);

    // PRODUCT_REVIEWS_STATS query
    useEffect(() => {
        if (
            hasQueryData(queryReviewStatsError, queryReviewStatsLoading, queryReviewStatsData)
            && queryReviewStatsData.reviewStats
        ) {
            const { reviewStats: { averageRating, ratingBreakdown, reviewCount } } = queryReviewStatsData;
            const ratingsArray = buildRatingsArray(ratingBreakdown);
            setProductReviewsData({
                ...productReviewsData,
                ratings: ratingsArray,
                totalCustomerReviews: reviewCount,
                averageRating
            });
        }
    }, [queryReviewStatsData, queryReviewStatsError, queryReviewStatsLoading]);

    // fetchMore paging
    useEffect(() => {
        if (productReviewsPaginatedData && productReviewsPaginatedData.reviews) {
            const updatedData = mapComponentData(
                productReviewsPaginatedData, data, fetchMore, setProductReviewsPaginatedData, refetch
            );
            // Load more reviews
            const newItems = [...productReviewsData.items, ...updatedData.items];
            setProductReviewsData({
                ...productReviewsData,
                ...updatedData,
                items: newItems
            });
        }
    }, [productReviewsPaginatedData]);

    return (
        <ProductReviewsComponent
            id={id}
            data={productReviewsData}
            settings={settings}
        />
    );
};

ProductReviewsAdapter.propTypes = {
    id: PropTypes.string,
    data: PropTypes.shape({
        i18n: PropTypes.shape({
            labels: PropTypes.shape({
                writeReview: PropTypes.string,
                basedOnReviews: PropTypes.string,
                currentPage: PropTypes.string,
                sortBy: PropTypes.string,
                latest: PropTypes.string,
                oldest: PropTypes.string,
                highestRated: PropTypes.string,
                lowestRated: PropTypes.string,
                reviews: PropTypes.string,
                noReviews: PropTypes.string
            })
        }),
        adTenant: PropTypes.string,
        baseUrl: PropTypes.string,
        addReviewUrl: PropTypes.string,
        productId: PropTypes.string,
        isLoggedIn: PropTypes.bool
    }),
    settings: PropTypes.shape({
        position: PropTypes.string,
        moreReviewsLabel: PropTypes.string
    })
};

ProductReviewsAdapter.defaultProps = {
    id: 'ProductReviews',
    data: {
        i18n: {
            labels: {
                writeReview: 'Write a Review',
                reviews: 'Reviews',
                basedOnReviews: 'Based on {n} reviews',
                noReviews: 'No customer reviews have been written.',
                sortBy: 'Sort by',
                latest: 'Most recent',
                oldest: 'Least recent',
                highestRated: 'Highest rated',
                lowestRated: 'Lowest rated',
                showFullReview: 'Show full review',
                hideFullReview: 'Show less'
            }
        },
        addReviewUrl: '/add-review',
        adTenant: 'APPDIRECT',
        baseUrl: 'http://localhost:3000',
        productId: 'cf6ab187-628b-4571-8089-d97319d68801',
        isLoggedIn: false
    },
    settings: {}
};

ProductReviewsAdapter.schema = ProductReviewsComponent.schema;

export default withGraphQL(ProductReviewsAdapter, 'api/reviews/graphql');
