import { useEffect } from 'react';
import { useSelector, useDispatch, batch } from 'react-redux';
import { companyDataSettingSelector } from '@root/store/companyDataSettings/companyDataSettings.selector';
import { scoringInputsResp } from '@root/store/scoringInputs/scoringInputs.selector';
import { progressTracker } from '@root/store/progressTracker/progressTracker.selector';
import { sizeAdjustmentsResp } from '@root/store/sizeAdjustments/sizeAdjustments.selector';
import { qAdjustmentsResp } from '@root/store/qAdjustments/qAdjustments.selector';
import { generatedScoreSelector } from '@root/store/generateScore/generateScore.selector';
import { parentAndGovernment } from '@root/store/parentAndGovernment/parentAndGovernment.selector';
import { loadPitAdjResp } from '@root/store/loadPitAdj/loadPitAdj.selector';
import {
    companyInformation as companyInformationSelector
} from '@root/store/companyInformation/companyInformation.selector';
import { formatDate } from '@utils/common';
import { trackerStatus, rgScoreIds, stepIds, restatementType, supportExpectations } from '@root/constants';
import {
    useGenerateScoreTrackerMutation,
    useGenerateScoreMutation, useGetRiskGaugeDataMutation
} from '@root/apis/generateScoreApi';
import {
    setGenerateScoreTracker,
    setGenerateScore, setLoadingState, setRiskGaugeData,
    setGenerateScorePayload,
    setPropUploaded
} from '@root/store/generateScore/generateScore.reducer';
import { addNotificationWrapper, useToastNotification } from '@spglobal/ca-mfe-package-utils/dist/hooks';
import { NotificationTypeWrapper} from '@spglobal/ca-mfe-package-utils';
import { useTranslation } from 'react-i18next';
import _ from 'lodash';
import { ActivityTracking,logActivity } from '@root/utils/activityTracking';
import { ActivityLogIds } from '@root/constants/activityLog';
import moment from 'moment';
import { userInformationResp } from '@root/store/userInformation/userInformation.selector';
import { isRgPlusUser } from '@root/store/userInformation/userInformation.reducer';


const getRGScoreIds = (steppers, pdConfig, isEPD = false, scoreIds = []) => {
    steppers.forEach(step => {
        if (step.isSubSection && step?.nestedSteps?.length) {
            getRGScoreIds(step.nestedSteps, pdConfig, isEPD, scoreIds);
        } else {
            if (step?.status === trackerStatus.COMPLETED && step?.showStep && step?.rgScoreId) {
                /**Below two cases where pdAdjsutment shouldn't be calculate:-
                 * case1 - should not calculate pdAdjsutment when standalone's oneToHunred score is zero
                 * case2 - should not calculate pdAdjsutment when isCCApplied is unchecked/false
                */
                if (step.rgScoreId !== rgScoreIds.PD_ADJ || (!pdConfig.isDefaultScore && pdConfig.isCCApplied)) {
                    scoreIds.push(step.rgScoreId);
                }
                if (isEPD && !scoreIds.includes(rgScoreIds.STANDALONE)) {
                    scoreIds.push(rgScoreIds.STANDALONE);
                }
            }
        }
    });
    return scoreIds;
};

const constructGenerateScorePayload = rawData => {
    const {
        companyData, companySelectedData, selectedValues,
        epdState, hasStates, scoringInputs, steppers, qAdjustments, isEsgSelected,
        sizeAdjustments, sizeAdjSections, prevScore,
        parentGovernment, selectedDataInputs, loadPitAdj, riskGaugePlusCap
    } = rawData;
    const scoringInputsData = scoringInputs?.currentResp?.data;
    const parentGovInputData = parentGovernment?.current?.data;
    const { periodDate, currency } = selectedDataInputs;
    const { companyId, csCompanyId, isUnlinkCompany } = companyData;
    const isEPD = typeof epdState?.scoreWithFinancials === 'boolean' && !epdState.scoreWithFinancials;
    const isDefaultScore = prevScore?.[rgScoreIds.STANDALONE]?.oneToHundred === 0;
    const isCCApplied = loadPitAdj?.currentResp?.creditCycle;
    const scoreIds = getRGScoreIds(steppers, { isDefaultScore, isCCApplied }, isEPD);

    if (!scoreIds?.length) {
        return null;
    }
    const scoringInputsPayload = inputsData => {
        const inputsObj = {};
        const { financial, nonFinancial } = inputsData || {};
        [...financial, ...nonFinancial].forEach(({ metrics }) => {
            if (metrics?.length) {
                metrics.forEach(mt => {
                    if (mt.analyticsName) {
                        inputsObj[mt.analyticsName] = mt?.numValue ?? '';
                    }
                });
            }
        });
        return inputsObj;
    };

    const setPgMetricsData = (pgMetrics, metricsObj) => {
        pgMetrics.forEach(({ metrics }) => {
            if (metrics?.length) {
                metrics.forEach(mt => {
                    if (mt.analyticsName && (mt?.numValue || mt?.strValue)) {
                        metricsObj[mt.analyticsName] = mt?.numValue ?? mt?.strValue;
                    }
                    if (mt.description === 'Metric' && mt?.strValue) {
                        metricsObj.PARENT_RATING_USED = mt?.strValue;
                    }
                    if (mt.analyticsName === 'SUPPORT_EXPECTATION' && !mt?.strValue) {
                        metricsObj.SUPPORT_EXPECTATION = supportExpectations.NEUTRAL.toUpperCase();
                    }
                });
            }
        });
        return metricsObj;
    };

    const parentAndGovPayload = inputsData => {
        let inputsObj: any = {};
        const pgMetrics = [];
        const { parent, government, nonFinPgMetrics } = inputsData || {};

        if (scoreIds.includes(rgScoreIds.Parent_ADJ) && parent) { pgMetrics.push(...parent); }
        if (scoreIds.includes(rgScoreIds.GOV_ADJ) && government) { pgMetrics.push(...government); }

        inputsObj = setPgMetricsData(pgMetrics, inputsObj);

        if (nonFinPgMetrics && inputsObj.PARENT_RATING_USED) {
            const nonFinPg = nonFinPgMetrics.find(metric => metric.key === inputsObj.PARENT_RATING_USED);
            if (nonFinPg) {
                inputsObj = setPgMetricsData([nonFinPg], inputsObj);
            }
        }
        return inputsObj;
    };

    const getVersion = riskGaugePlusCap => riskGaugePlusCap ? 'V3' : 'V2';

    const transformedRequest: any = {
        rgScoreIds: scoreIds,
        loadInputsRequest: {
            ...(!isUnlinkCompany && { companyId }),
            ...(csCompanyId && { csCompanyId }),
            asOfDate: selectedValues?.scoreDate,
            countryIsoCode: companySelectedData?.country?.value,
            industryCode: companySelectedData?.industry?.value,
            currencyIso: selectedValues?.currency?.value,
            publicPrivate: companySelectedData?.type.value,
            scoreWithFinancials: selectedValues?.financialType === '0',
            ...(isEPD && {epdPeriod: selectedValues?.selectPeriod?.value?.toString()}),
            ...(hasStates && {state: (()=> companySelectedData?.state?.code
                 || companySelectedData?.state?.value)()})
        },
        version: getVersion(riskGaugePlusCap)
    };

    if (scoreIds.includes(rgScoreIds.STANDALONE) && scoringInputsData) {
        transformedRequest.inputsData = scoringInputsPayload(scoringInputsData);
    }

    if (scoreIds.includes(rgScoreIds.SIZE_ADJ)) {
        const { currentResp } = sizeAdjustments;
        const selectedSizeAdjValues = currentResp?.data;
        const { totalAssets, totalEmployees, totalRevenue } = sizeAdjSections;

        const getRevenueRangeNum = revenueRange => {
            const bucket = selectedSizeAdjValues?.revenueBuckets?.find(item => item.displayValue === revenueRange);
            return bucket ? `${bucket?.lowerBound}-${bucket?.upperBound}` : null;
        };

        transformedRequest.sizeAdjustment = {
            TOTAL_EMPLOYEES: totalEmployees ? selectedSizeAdjValues?.totalEmployees?.value : null,
            TOTAL_REVENUE: totalRevenue ? getRevenueRangeNum(selectedSizeAdjValues?.totalRevenue?.revenueRange) : null,
            TOTAL_ASSETS: totalAssets ? selectedSizeAdjValues?.totalAssets?.value : null
        };
    }

    if (scoreIds.includes(rgScoreIds.Q_ADJ)) {
        const { currentResp } = qAdjustments;

        const getQAdjValues = values => {
            const { displayValues, defaultValue } = values;
            const result = displayValues.find(item => item?.displayName === defaultValue);
            return [defaultValue?.toUpperCase(), result?.value];
        };

        transformedRequest.qualAdjustment = {
            competitivePosition: getQAdjValues(currentResp?.data[0]),
            diversificationFactor: getQAdjValues(currentResp?.data[1]),
            capitalStructure: getQAdjValues(currentResp?.data[2]),
            financialPolicy: getQAdjValues(currentResp?.data[3]),
            qualityOfManagementFactor: getQAdjValues(currentResp?.data[4]),
            paymentBehaviorFactor: getQAdjValues(currentResp?.data[5])
        };

        (()=>{
            if(riskGaugePlusCap && isEsgSelected) {
                transformedRequest.esgAdjustment = {
                    environmental: getQAdjValues(currentResp?.data[6]),
                    social: getQAdjValues(currentResp?.data[7]),
                    governance: getQAdjValues(currentResp?.data[8])
                };
            }
        })();
    }

    if (scoreIds.includes(rgScoreIds.Parent_ADJ) || scoreIds.includes(rgScoreIds.GOV_ADJ)) {
        transformedRequest.parentAndGov = {
            ...transformedRequest.parentAndGov,
            ...parentAndGovPayload(parentGovInputData),
            CURRENCYCODE_PARENT: currency?.value,
            DATA_SOURCE_PARENT: periodDate?.restatementType || restatementType.LC,
            FINANCIAL_STATEMENT_DATE_PARENT: formatDate(periodDate?.periodDate, 'YYYY-MM-DD'),
            PERIOD_TYPE_PARENT: periodDate?.periodType
        };
    }

    if (scoreIds.includes(rgScoreIds.PD_ADJ) && !isDefaultScore && isCCApplied) {
        const { currentResp } = loadPitAdj;
        transformedRequest.pdAdjustment = {
            isCCApplied,
            adjustmentDate: formatDate(currentResp?.pitAdjustmentDate || new Date(), 'YYYY-MM-DD')
        };
    }

    transformedRequest.previousAdjustments = prevScore;

    return transformedRequest;
};

const useGenerateScore = () => {
    const dispatch = useDispatch();
    const [generateScoreTracker] = useGenerateScoreTrackerMutation();
    const [generateScore] = useGenerateScoreMutation();
    const [getRiskGaugeData] = useGetRiskGaugeDataMutation();
    const { selectedValues } = useSelector(companyDataSettingSelector);
    const { scoringInputs } = useSelector(scoringInputsResp);
    const { steppers, activeStep } = useSelector(progressTracker);
    const { sizeAdjustments, sizeAdjSections } = useSelector(sizeAdjustmentsResp);
    const { qAdjustments, isEsgSelected } = useSelector(qAdjustmentsResp);
    const scoredTrackerData = useSelector(generatedScoreSelector);
    const { companySelectedData, companyData, epdState, hasStates } = useSelector(companyInformationSelector);
    const { parentGovernment, selectedDataInputs } = useSelector(parentAndGovernment);
    const { loadPitAdj } = useSelector(loadPitAdjResp);
    const { addNotification } = useToastNotification();
    const logId = ActivityLogIds.CA_RG_SCORING_GENERATE_SCORE;
    const { companyId, csCompanyId, isUnlinkCompany } = companyData;
    const { t } = useTranslation();
    const activityTrackingObj = ActivityTracking();
    const { userInfo } = useSelector(userInformationResp);
    const riskGaugePlusCap = useSelector(isRgPlusUser);
    const rgPlusStandalone = [
        'pdCreditScore', 'pdScoreOneToHundred', 'creditRiskScore','pd',
        'pdmsCreditScore', 'bondBenchmarkCreditScore', 'bisCreditScore'
    ];
    const rgPlusQualitative = ['Q_PD_SCORE_LETTER_GRADE', 'Q_PD_SCORE',
        'Q_PD_SCORE_CREDIT_WORTHINESS', 'Q_PD_SCORE_1_100', 'Q_PD_SCORE_RISKTYPE'];
    const isEPD = typeof epdState?.scoreWithFinancials === 'boolean' && !epdState.scoreWithFinancials;
    const rgVersion3 = (userInfo?.rgModelVersion === 3 || userInfo?.rGModelVersion === 3);
    const rgPlusPg = [
        'PG_SUPPORT_STANDALONE_PD_CREDIT_WORTHINESS',
        'PG_SUPPORT_STANDALONE_PD',
        'PG_SUPPORT_STANDALONE_PD_1_100',
        'PG_SUPPORT_STANDALONE_PD_RISKTYPE',

        'GRE_OVERLAY_STANDALONE_PD',
        'GRE_OVERLAY_STANDALONE_PD_1_100',
        'GRE_OVERLAY_STANDALONE_PD_CREDIT_WORTHINESS',
        'GRE_OVERLAY_STANDALONE_PD_RISKTYPE',
        'PARENTAL_SUPPORT_STANDALONE_PD',
        'PARENTAL_SUPPORT_STANDALONE_PD_1_100',
        'PARENTAL_SUPPORT_STANDALONE_PD_CREDIT_WORTHINESS',
        'PARENTAL_SUPPORT_STANDALONE_PD_RISKTYPE'
    ];
    const fnCmProps = [
       'TOTAL_REVENUE','TOTAL_ASSETS','TOTAL_LIABILITY','TOTAL_DEBT','INTANGIBLE_ASSETS'
    ];
    const rgProps = [
        'rgCreditScore', 'rgScoreBasicView', 'rgScoreOneToNine', 'rgScoreOneToHundred', 'rgPd',
        'pdmsCreditScore'
    ];
    const getFormattedDate = date => date && moment(date).format('YYYY-MM-DD') || null;
    const periodDate = selectedValues => selectedValues?.financialType === '0' ?
                getFormattedDate(selectedValues?.financialStatement?.periodDate):
                getFormattedDate(selectedValues?.selectPeriod?.periodDate);

    const periodType = selectedValues => selectedValues?.financialType === '0' ? selectedValues?.periodType?.label : 'FY';
    const periodYear = selectedValues => selectedValues?.financialType === '0' ?
                        selectedValues?.financialStatement?.fiscalYear : selectedValues?.selectPeriod?.value;

    const fetchGeneratedScoreTracker = async prevScore => {
        dispatch(setLoadingState({ trackerScoreLoader: true }));
        const transformedRequest = constructGenerateScorePayload({
            selectedValues,
            companySelectedData,
            companyData,
            epdState,
            hasStates,
            scoringInputs,
            steppers,
            activeStep,
            sizeAdjustments,
            sizeAdjSections,
            qAdjustments,
            isEsgSelected,
            scoredTrackerData,
            prevScore,
            parentGovernment,
            selectedDataInputs,
            loadPitAdj,
            riskGaugePlusCap
        });
        if (transformedRequest !== null) {
            const apiPromises = [];
            apiPromises.push(generateScoreTracker(transformedRequest));
            if (activeStep.stepId === stepIds.RG_SCORE) {
                dispatch(setGenerateScorePayload(transformedRequest));
                dispatch(setPropUploaded(false));
            apiPromises.push(generateScore(transformedRequest));
            logActivity(logId,activityTrackingObj);
        }
            const [trackerScoreResp, scoreResp] = await Promise.all(apiPromises);
            dispatch(setGenerateScoreTracker(trackerScoreResp?.data?.data || {}));
            if (scoreResp) {
                dispatch(setGenerateScore(scoreResp?.data?.data || {}));
                if (scoreResp?.data?.error) {
                    addNotificationWrapper(t('scoringui:errorNotificationMsg'),
                        NotificationTypeWrapper.ERROR, addNotification);
                    dispatch(setLoadingState({ scoreLoader: false }));
                }
                if ([false].includes(scoreResp?.data?.data?.scoringStatus?.hasError)) {
                    const updatePayload = data => {
                        const respData = _.cloneDeep(data);
                        const getRequiredProps = (obj, keys) => {
                            if (!obj || obj?.errorMessage) {
                                return { errorMessage: obj?.errorMessage || ''};
                            }

                            const newObj = {};
                            keys.forEach(key => {
                                newObj[key] = obj[key];
                            });
                            return newObj;
                        };
                        const fnCmCheck = !isEPD && (rgVersion3);
                        delete respData.scoringStatus;
                        respData.scoringData[0] = {
                            riskgauge: respData.scoringData[0].riskgauge,
                            ...( fnCmCheck ? {fn: respData.scoringData[0].fn ,
                            cm: respData.scoringData[0].cm} : ''),
                            ...(isEPD && {epd: respData.scoringData[0].epd}),
                            'Filing Currency': respData.scoringData[0]['Filing Currency']
                        };
                        if(typeof respData?.scoringData[0]?.riskgauge?.rgAbsContribution === 'string'){
                            respData.scoringData[0].riskgauge.rgAbsContribution = null;
                        }
                        delete respData.scoringData[0].riskgauge.pdms;
                        delete respData.scoringData[0].riskgauge.bond;
                        respData.scoringData[0].riskgauge.rgStandalone =
                         getRequiredProps(respData.scoringData[0].riskgauge.rgStandalone,
                             riskGaugePlusCap ? rgPlusStandalone : rgProps);

                        if(riskGaugePlusCap){
                            respData.scoringData[0].riskgauge.qualitative =
                                getRequiredProps(respData.scoringData[0].riskgauge.qualitative, rgPlusQualitative);
                            respData.scoringData[0].riskgauge.rgPg =
                                getRequiredProps(respData.scoringData[0].riskgauge.rgPg, rgPlusPg);
                            if(!isEPD && (rgVersion3)){
                            respData.scoringData[0].fn =
                                getRequiredProps(respData.scoringData[0].fn, fnCmProps);
                            respData.scoringData[0].cm =
                                getRequiredProps(respData.scoringData[0].cm, fnCmProps);
                            }
                        } else {
                            respData.scoringData[0].riskgauge.rgSov =
                                getRequiredProps(respData.scoringData[0].riskgauge.rgSov, rgProps);
                            respData.scoringData[0].riskgauge.rgSovPG =
                                getRequiredProps(respData.scoringData[0].riskgauge.rgSovPG, rgProps);
                        }

                        return respData;
                    };

                    const isAdjStepSelected = stepId => {
                        const adjSteps= steppers.find(step=>(step.stepId === stepIds.ADJUSTMENTS))?.nestedSteps || [];
                        return (
                            Boolean(adjSteps?.find(adjStep=>(
                                adjStep.status!=='notSelected' && adjStep.stepId===stepId
                            )))
                        );
                    };

                    const isQaAdjSelected = isAdjStepSelected(stepIds.QUALITATIVE_ADJUSTMENTS);
                    const isParentSelected = isAdjStepSelected(stepIds.PARENT_ADJUSTMENTS);
                    const isSizeAdjSelected = isAdjStepSelected(stepIds.SIZE_ADJUSTMENTS);
                    const isPitAdjSelected = isAdjStepSelected(stepIds.Pd_ADJUSTMENTS);
                    const isGovSelected = isAdjStepSelected(stepIds.GOVERNMENT_SUPPORT);
                    const sizeAdjObj = sizeAdjustments?.currentResp?.data;
                    const resp = await getRiskGaugeData({
                        inputRequest: {
                            ...(!isUnlinkCompany && { companyId }),
                            ...(csCompanyId && { csCompanyId }),
                            asOfDate: selectedValues?.scoreDate,
                            countryIsoCode: companySelectedData?.country?.value,
                            industryCode: companySelectedData?.industry?.value,
                            pitAdjustmentDate: formatDate(loadPitAdj?.currentResp?.pitAdjustmentDate || new Date(),
                                'YYYY-MM-DD'),
                            isPitApplied: loadPitAdj?.currentResp?.creditCycle && isPitAdjSelected,
                            periodQuarter: selectedValues?.financialType === '0' ?
                                selectedValues?.financialStatement?.fiscalQuarter : 4,
                            periodType: periodType(selectedValues),
                            periodYear: periodYear(selectedValues),
                            statementDate: periodDate(selectedValues),
                            isQaAdjSelected,
                            isSizeAdjSelected,
                            isParentSelected,
                            isGovSelected,
                            ...(hasStates && {state: (()=> companySelectedData?.state?.code
                                || companySelectedData?.state?.value)()}),
                            primaryScale: userInfo?.selectedRgPrimayScoreEnum,
                            hasRgTransitionalUserCap: userInfo?.hasRgTransitionalUserCap,
                            ...(isEPD && rgVersion3 &&
                                {totalEmployees: sizeAdjSections?.totalEmployees ? sizeAdjObj.totalEmployees?.value : null,
                                medianRevenue:
                                sizeAdjSections?.totalRevenue ? sizeAdjObj?.totalRevenue?.value?.split('M')[0]: null ,
                                totalAssets: sizeAdjSections?.totalAssets ? sizeAdjObj?.totalAssets?.value : null})
                         },
                        generatedScore: updatePayload(scoreResp?.data?.data),
                        version: riskGaugePlusCap ? 'V3' : 'V2'
                    });
                    if (resp?.error) {
                        addNotificationWrapper(t('scoringui:errorNotificationMsg'),
                            NotificationTypeWrapper.ERROR, addNotification);
                        dispatch(setLoadingState({ scoreLoader: false }));
                    } else {
                        dispatch(setRiskGaugeData(resp?.data?.data));
                    }
                } else {
                    dispatch(setLoadingState({ scoreLoader: false }));
                }
            }
        } else {
            dispatch(setLoadingState({ trackerScoreLoader: false }));
        }
    };
    useEffect(() => {
        const { asOfDate, prevAsOfDate } = selectedValues;
        const isAsOfDateChanged = Boolean(asOfDate !== prevAsOfDate);
        const isScoringInputStep = Boolean(stepIds.SCORING_INPUTS === activeStep.stepId);
        const generatedScoreTracker = _.cloneDeep(scoredTrackerData?.generatedScoreTracker);
        if (isScoringInputStep) {
            if (isAsOfDateChanged) {
                delete generatedScoreTracker?.rgBenchmark;
                fetchGeneratedScoreTracker(generatedScoreTracker);
            } else {
                delete generatedScoreTracker?.standalone;
                dispatch(setGenerateScoreTracker(generatedScoreTracker));
            }
        } else {
            fetchGeneratedScoreTracker(generatedScoreTracker);
        }
        return () => {
            batch(() => {
                dispatch(setRiskGaugeData({}));
                dispatch(setLoadingState({ scoreLoader: true }));
            });
        };
    }, [activeStep?.stepId]);
    return null;
};

export default useGenerateScore;
