import React, { useMemo, useState } from 'react';
import PropTypes from 'prop-types';
import { useForm } from 'react-hook-form';
import merge from 'deepmerge';

import withListener from '../withListener';
import { createNamespace } from '../../tools/namingTools';
import RatingInput from '../../atoms/rating-input/RatingInput';
import ProductCard from '../../atoms/product-card/ProductCard';
import { PRODUCT_DEFAULT_IMG } from '../../constants/images';
import Button from '../../atoms/button/Button';
import ButtonIcon from '../../atoms/button-icon/ButtonIcon';
import Input from '../../atoms/input/Input';
import Textarea from '../../atoms/textarea/Textarea';
import GridContainer from '../../atoms/grid-container/GridContainer';
import Icon from '../../atoms/icon/Icon';
import { XSMALL } from '../../constants/sizes';
import Alert, { alertTypes } from '../../atoms/alert/Alert';
import { getCookieValue } from '../../tools/helpers';
import { addAlert, ALERT_REVIEW_ADD_SUCCESS } from '../../tools/alerts';
import Preloader from '../../atoms/preloader/Preloader';
// IMPORTANT: (s)css should be imported after other atoms/components
import './styles/ProductReviewForm.scss';

const n = createNamespace('ProductReviewForm');

const REVIEW_MAX_LENGTH = 2048;

export const ProductReviewFormComponent = ({
    data: {
        summary,
        productUrl,
        actionEndpoint,
        i18n
    }
}) => {
    const { handleSubmit, register, errors } = useForm();

    const [errorStatus, setErrorStatus] = useState(false);
    const [isSubmitting, setIsSubmitting] = useState(false);

    const onSubmit = values => {
        setIsSubmitting(true);
        const payloadString = JSON.stringify(values);

        const XHR = new XMLHttpRequest();
        const success = [200, 201, 202, 204];

        // Define what happens on successful data submission
        XHR.addEventListener('load', () => {
            if (success.includes(XHR.status)) {
                addAlert(ALERT_REVIEW_ADD_SUCCESS);
                window.location.assign(productUrl);
            } else {
                setErrorStatus(true);
                setIsSubmitting(false);
            }
        });

        // Define what happens in case of error
        XHR.addEventListener('error', () => {
            setErrorStatus(true);
            setIsSubmitting(false);
        });

        XHR.open('POST', actionEndpoint);
        XHR.setRequestHeader('Content-Type', 'application/json');
        XHR.setRequestHeader('X-XSRF-TOKEN', getCookieValue('XSRF-TOKEN'));
        XHR.send(payloadString);
    };

    const closeForm = () => {
        window.location.assign(productUrl);
    };

    // memoize i18n defaults merge, as it does not change from state to state
    const i18nWithDefaults = useMemo(
        () => (
            merge(ProductReviewFormComponent.defaultProps.data.i18n, i18n)
        ),
        [ProductReviewFormComponent.defaultProps.data.i18n, i18n]
    );

    return (
        <section {...n('wrapper').withTestId().props}>
            <GridContainer {...n('container').props}>
                <div {...n('content').props}>
                    <h1 {...n('title').props}>{i18nWithDefaults.labels.writeReview}</h1>
                    <div {...n('closeButton').props}>
                        <Button buttonType="icon" onClick={closeForm} aria-label={i18n.labels.close}>
                            <Icon {...n('closeButtonIcon').props} type="close" />
                        </Button>
                    </div>
                    <div {...n('productCard').props} key="info">
                        <ProductCard
                            cardData={{ ...summary, size: XSMALL.value }}
                            settings={{
                                showRatings: false,
                                productNameSize: XSMALL.value,
                                descTextSize: XSMALL.value
                            }}
                        />
                    </div>
                    {errorStatus && (
                        <Alert
                            alertMessage={i18nWithDefaults.messages.error.postEntry}
                            type={alertTypes.ERROR_ALERT}
                            onClick={() => setErrorStatus(false)}
                            scrollIntoView
                            closeAlert={i18n.labels.closeAlert}
                        />
                    )}
                    <form onSubmit={handleSubmit(onSubmit)} {...n('wrapper').withTestId('form').props}>
                        <fieldset {...n('fieldset').props} key="rating">
                            <legend {...n('legend', 'required').props}>{i18nWithDefaults.labels.myRating}</legend>
                            <div {...n('formGroup').props}>
                                <RatingInput
                                    name="rating"
                                    value={0}
                                    height={35}
                                    i18n={i18nWithDefaults}
                                    error={errors.rating && errors.rating.message}
                                    inputRef={register({
                                        required: {
                                            value: true,
                                            message: i18nWithDefaults.messages.error.ratingRequired
                                        }
                                    })}
                                />
                            </div>
                        </fieldset>
                        <fieldset {...n('fieldset').props} key="headline">
                            <legend {...n('legend', 'required').props}>{i18nWithDefaults.labels.headlineLabel}</legend>
                            <div {...n('formGroup').props}>
                                <Input
                                    name="title"
                                    hiddenLabel
                                    error={errors.title && errors.title.message}
                                    label={i18nWithDefaults.labels.headlinePlaceholder}
                                    placeholder={i18nWithDefaults.labels.headlinePlaceholder}
                                    aria-labelledby="headlineCaption"
                                    inputRef={register({
                                        required: {
                                            value: true,
                                            message: i18nWithDefaults.messages.error.headlineRequired
                                        }
                                    })}
                                />
                            </div>
                            <p {...n('description').props} id="headlineCaption">{i18nWithDefaults.labels.headlineDescription}</p>
                        </fieldset>
                        <fieldset {...n('fieldset').props} key="review">
                            <legend {...n('legend').props}>{i18nWithDefaults.labels.reviewLabel}</legend>
                            <p {...n('description', 'required').props} id="reviewCaption">{i18nWithDefaults.labels.reviewDescription}</p>
                            <div {...n('formGroup').props}>
                                <Textarea
                                    name="comment"
                                    hiddenLabel
                                    error={errors.comment && errors.comment.message}
                                    label={i18nWithDefaults.labels.reviewPlaceholder}
                                    placeholder={i18nWithDefaults.labels.reviewPlaceholder}
                                    aria-labelledby="reviewCaption"
                                    inputRef={register({
                                        required: {
                                            value: true,
                                            message: i18nWithDefaults.messages.error.descriptionRequired
                                        },
                                        maxLength: {
                                            value: REVIEW_MAX_LENGTH,
                                            message: i18nWithDefaults.messages.error.textareaMaxLength
                                        }
                                    })}
                                />
                            </div>
                        </fieldset>
                        <div {...n('btnContainer').props} key="submit">
                            <ButtonIcon type="button" theme="primary" action="submit" disabled={isSubmitting}>
                                {i18nWithDefaults.labels.submit}
                            </ButtonIcon>
                        </div>
                    </form>
                </div>
            </GridContainer>
            <Preloader isLoading={isSubmitting} />
        </section>
    );
};

ProductReviewFormComponent.schema = () => ({
    name: 'ProductReviewForm',
    title: 'uieditor.sfbComponent.productReviewForm.title',
    form: {},
    marketplaceData: {
        summary: 'application.summary',
        actionEndpoint: 'application.reviews.actionEndpoint',
        productUrl: 'application.reviews.productUrl',
        i18n: 'application.reviews.i18n'
    }
});

ProductReviewFormComponent.propTypes = {
    data: PropTypes.shape({
        summary: PropTypes.shape({
            title: PropTypes.string,
            details: PropTypes.string,
            logoSrc: PropTypes.string,
            logoSrcset: PropTypes.shape({
                default: PropTypes.string,
                '2x': PropTypes.string,
                '1x': PropTypes.string
            })
        }),
        actionEndpoint: PropTypes.string,
        productUrl: PropTypes.string,
        i18n: PropTypes.shape({
            labels: PropTypes.shape({
                edit: PropTypes.string,
                delete: PropTypes.string,
                cancel: PropTypes.string,
                close: PropTypes.string,
                confirm: PropTypes.string,
                submit: PropTypes.string,
                myReview: PropTypes.string,
                myRating: PropTypes.string,
                signup: PropTypes.string,
                writeReview: PropTypes.string,
                reviews: PropTypes.string,
                reviewDetails: PropTypes.string,
                description: PropTypes.string,
                title: PropTypes.string,
                singleStar: PropTypes.string,
                multiStars: PropTypes.string,
                headlineLabel: PropTypes.string,
                headlinePlaceholder: PropTypes.string,
                headlineDescription: PropTypes.string,
                reviewLabel: PropTypes.string,
                reviewPlaceholder: PropTypes.string,
                reviewDescription: PropTypes.string,
                ratingLevel1: PropTypes.string,
                ratingLevel2: PropTypes.string,
                ratingLevel3: PropTypes.string,
                ratingLevel4: PropTypes.string,
                ratingLevel5: PropTypes.string,
                closeAlert: PropTypes.string
            }),
            messages: PropTypes.shape({
                success: PropTypes.shape({
                    postComment: PropTypes.string
                }),
                error: PropTypes.shape({
                    postEntry: PropTypes.string,
                    textareaMaxLength: PropTypes.string,
                    fieldRequired: PropTypes.string,
                    mustBeBetween: PropTypes.string,
                    ratingRequired: PropTypes.string,
                    headlineRequired: PropTypes.string,
                    descriptionRequired: PropTypes.string
                })
            })
        })
    })
};

ProductReviewFormComponent.defaultProps = {
    data: {
        summary: {
            title: null,
            details: null,
            logoSrc: PRODUCT_DEFAULT_IMG,
            logoSrcset: {
                default: null,
                '2x': null,
                '1x': null
            }
        },
        productUrl: '',
        actionEndpoint: '',
        i18n: {
            labels: {
                edit: 'Edit',
                delete: 'Delete',
                cancel: 'Cancel',
                close: 'Close the review form',
                confirm: 'Confirm',
                submit: 'Submit',
                myReview: 'My Review',
                myRating: 'My Rating',
                signup: 'Sign Up to Write a Review',
                writeReview: 'Write a Review',
                reviews: 'Reviews',
                reviewDetails: 'Review Details',
                description: 'Description',
                title: 'Title',
                singleStar: ' star',
                multiStars: ' stars',
                headlineLabel: 'Write a headline',
                headlinePlaceholder: 'Review headline',
                headlineDescription: 'Write a short headline sharing the most important things to know',
                ratingLabel: 'Select youir rating',
                ratingLevel1: 'Poor',
                ratingLevel2: 'Fair',
                ratingLevel3: 'Average',
                ratingLevel4: 'Good',
                ratingLevel5: 'Excellent',
                reviewLabel: 'Write your review',
                reviewPlaceholder: 'Review description',
                reviewDescription: 'What did you like most or least about this product?',
                closeAlert: 'Close alert'
            },
            messages: {
                success: {
                    postEntry: 'Thank you for the review, it will be posted shortly'
                },
                error: {
                    postEntry: 'You must log in to write a review.',
                    textareaMaxLength: 'Must be at most 2048 characters',
                    fieldRequired: 'Required',
                    mustBeBetween: 'Must be between 1 and 5',
                    ratingRequired: 'Error: Please select a rating option for your review',
                    headlineRequired: 'Error: Headline is required',
                    descriptionRequired: 'Error: Description is required'
                }
            }
        }
    }
};

export default withListener(ProductReviewFormComponent);
