import { IEdmundAbbottBodyV2, IRule } from '@rh-support/api';
import { IMainSectionProps } from '@rh-support/types';
import isEmpty from 'lodash/isEmpty';
import map from 'lodash/map';
import React, { forwardRef, useContext, useEffect, useReducer, useState } from 'react';
import { RouteComponentProps } from 'react-router';
import { AppMetadataStateContext } from '../../context/AppMetadataContext';
import { CreateCaseStateContext } from '../../context/CreateCaseContext';
import { RouteContext, RouteDispatchContext } from '../../context/RouteContext';
import { RulesDispatchContext, RulesStateContext } from '../../context/RulesContext';
import { AppRouteSections, IRouteUrlParams, RouteReducerConstants } from '../../reducers/RouteReducer';
import { fetchEdmundAbbottRules, setEARulesVisibilityChange } from '../../reducers/RulesReducer';
import { fetchTopContent, initialTopContentState, topContentReducer } from '../../reducers/TopContentReducer';
import AlertMessage, { AlertType } from '../shared/AlertMessage';
import LoadingIndicator from '../shared/LoadingIndicator';
import Rule from '../shared/Rule';
import TopContent from './TopContent';

interface IProps extends IMainSectionProps {
    routeProps: RouteComponentProps<IRouteUrlParams>;
}

const defaultProps: Partial<IProps> = {
    id: '',
    className: ''
};

export const Suggestions = forwardRef<HTMLDivElement, IProps>((props, ref) => {

    // internal reducer
    const [hasNoResult, setHasNoResult] = useState(false);

    // internal reducer states
    const [topContentState, dispatchTopContent] = useReducer(topContentReducer, initialTopContentState);

    // global states
    const rulesDispatch = useContext(RulesDispatchContext);
    const { rulesState } = useContext(RulesStateContext);
    const { appMetadataState: {guid, loggedInUser, loggedInUsersAccount} } = useContext(AppMetadataStateContext);
    const { createCaseState: { product, version } } = useContext(CreateCaseStateContext);
    const { routeState: { activeSection, isSectionValid, appRouteConfugurations, sectionsToHide } } = useContext(RouteContext);
    const dispatchToRouteReducer = useContext(RouteDispatchContext);

    // Hiding Suggestions section
    useEffect(() => {
        if (activeSection !== AppRouteSections.SUGGESTIONS) { return; }
        if (!topContentState.isLoadingTopContent
            && !rulesState.isLoadingEdmundAbbottRules
            && topContentState.topContentResponse.length === 0
            && rulesState['EARules'].rules.length === 0
        ) {
            dispatchToRouteReducer({ type: RouteReducerConstants.updateSectionsToHide, payload: { sectionsToHide: sectionsToHide.concat(AppRouteSections.SUGGESTIONS) } });
            setHasNoResult(true);
        } else {
            setHasNoResult(false);
        }
    }, [topContentState.topContentResponse, topContentState.isLoadingTopContent, rulesState.isLoadingEdmundAbbottRules, rulesState['EARules']]);

    useEffect(() => {
        if (isEmpty(product) || activeSection !== AppRouteSections.SUGGESTIONS) { return; }
        activeSection === AppRouteSections.SUGGESTIONS &&
            !loggedInUser.isError && !loggedInUser.isError &&
            !loggedInUsersAccount.isFetching && !loggedInUsersAccount.isError &&
            getSuggestions(window.sessionjs);
    }, [product, version, activeSection, loggedInUser, loggedInUsersAccount]);

    // Validations effect
    useEffect(() => {
        if (activeSection !== AppRouteSections.SUGGESTIONS) { return; }
        const isSectionValidLocal = !isLoading();
        if (isSectionValid === isSectionValidLocal) { return; }
        dispatchToRouteReducer({ type: RouteReducerConstants.setIsSectionValid, payload: { isSectionValid: isSectionValidLocal } });
    }, [activeSection, rulesState.isLoadingEdmundAbbottRules, topContentState.isLoadingTopContent, loggedInUser, loggedInUsersAccount]);

    async function getSuggestions(session) {
        if (activeSection !== AppRouteSections.SUGGESTIONS) { return; }
        const rulesBody: IEdmundAbbottBodyV2 = {
            caseType: {
                product, version,
                accountNumber: session.getUserInfo().account_number,
                owner: null,
                language: null,
                caseNumber: null
            },
            accountType: { isSecure: loggedInUsersAccount.data.is_secure || false },
            userType: { canAddAttachments: loggedInUser.data.can_add_attachments || false },
            fields: ['title', 'cta', 'description', 'rule_type', 'rule_sub_type']
        };
        await Promise.all([
            fetchTopContent(dispatchTopContent, { product, version }),
            fetchEdmundAbbottRules(rulesDispatch, rulesBody)
        ]);
    }

    const onHide = (cta: string) => {
        setEARulesVisibilityChange(rulesDispatch, { 'cta': cta });
    };

    const showRule = (rule: IRule) => (
        rule.visible &&
        <Rule onHide={onHide.bind(null, rule.cta)}
            description={rule.description}
            title={rule.title}
            link={rule.cta}
            key={rule.cta} />
    );

    const isLoading = (): boolean => {
        return !hasError() && (activeSection === AppRouteSections.SUGGESTIONS && (rulesState.isLoadingEdmundAbbottRules ||
            topContentState.isLoadingTopContent ||
            loggedInUser.isFetching ||
            loggedInUsersAccount.isFetching));
    };

    const hasError = (): boolean => {
        return rulesState.isLoadingEdmundAbbottRulesError ||
            topContentState.isLoadingTopContentError ||
            loggedInUser.isError ||
            loggedInUsersAccount.isError;
    };

    return (
        <section className={`${props.className}`} id={`${props.id}`} ref={ref} tabIndex={-1} aria-labelledby="suggestionsSecHeading" aria-describedby="suggestionsSecDescription">
            <LoadingIndicator show={isLoading()} size="lg" />
            <AlertMessage type={AlertType.DANGER} className="push-top" message="There was an error loading suggestions." show={hasError()} />
            {!isLoading() && !hasError() &&
                <>
                    <header>
                        <h2 id="suggestionsSecHeading">{appRouteConfugurations[AppRouteSections.SUGGESTIONS].title}</h2>
                        <p id="suggestionsSecDescription">These categories include common issue topics and solutions for your product.</p>
                    </header>
                    {hasNoResult && <p>No suggestion Found.</p>}
                    {map(rulesState['EARules'].rules, (rule) => showRule(rule))}
                    <pfe-accordion>
                        {map(topContentState.topContentResponse, (sug, i) => (<TopContent guid={guid.data} name={sug.name} key={sug.name} items={sug.items} />))}
                    </pfe-accordion>
                    <p className="push-top-wide">If you need more help, you can give details on your specific issue in the next step.</p>
                </>
            }
        </section>
    );
});
Suggestions.defaultProps = defaultProps;
export default Suggestions;
