import {
    getAccountDetails,
    getCaseGroupsForSSO,
    getCaseTypes,
    getEntitelmentsForContact,
    getGuid,
    getSEProductsList,
    getSeverities,
    getStrataUser,
    IGroup,
    IStrataAccountResponse,
    IStrataEntitlement,
    IStrataMetadataValue,
    IStrataUser,
    setStrataHeaders
} from '@rh-support/api';
import { IAction, IApiResponseDetails, IPortalJwtToken } from '@rh-support/types';
import hydrajs from 'hydrajs';
import { IMaintenance } from 'hydrajs/types/src/models/maintenance';
import get from 'lodash/get';
import isEmpty from 'lodash/isEmpty';
import orderBy from 'lodash/orderBy';
import CaseUtils from '../utils/caseUtils';
import { getProcessedEntitlements, handleProductSearchResponse } from './AppMetadataHelpers';

// Interfaces
export type ICaseType = IStrataMetadataValue;
export type ICaseSeverity = IStrataMetadataValue;
export type ICaseEntitlement = IStrataEntitlement;
export type IVersion = string;

// Product returned from API call
export interface IProductBeckend {
    featuredVersion: IVersion;
    product_name: string;
    versions: IVersion[];
}
export type IProduct = IProductBeckend & {
    selectedVersion?: IVersion;
};
export interface IProductResponse {
    topProducts: IProduct[];
    otherProducts: IProduct[];
    productsResult: IProduct[];
}
export interface IIntraction {
    time: Date;
    action: string;
    context: string[];
}
export interface IAppMetadataState {
    allCaseTypes: IApiResponseDetails<ICaseType[]>;
    allCaseSeverities: IApiResponseDetails<ICaseSeverity[]>;
    allCaseEntitlements: IApiResponseDetails<ICaseEntitlement[]>;
    allProducts: IApiResponseDetails<IProductResponse>;
    loggedInUsersAccount: IApiResponseDetails<Partial<IStrataAccountResponse>>;
    loggedInUser: IApiResponseDetails<Partial<IStrataUser>>;
    loggedInUserJwtToken: Partial<IPortalJwtToken>;
    caseLanguages: IApiResponseDetails<string[]>;
    caseGroups: IApiResponseDetails<IGroup[]>;
    guid: IApiResponseDetails<string>;
    trackingProductFlag: boolean;
    pcmConfig: IApiResponseDetails<IMaintenance[]>;
    nextButtonRef: React.MutableRefObject<HTMLButtonElement>;
}

export interface IAppMetadataPayloadType extends IAppMetadataState {
    interaction: IIntraction;
}
type IActionType = IAction<AppMetadataReducerConstants, IAppMetadataPayloadType>;
export type AppMetadataReducerDispatchType = (value: IActionType) => void;

// Constants
export enum AppMetadataReducerConstants {
    setCaseTypes = 'setCaseTypes',
    setCaseSeverities = 'setCaseSeverities',
    setCaseEntitlements = 'setCaseEntitlements',
    setAllProducts = 'setAllProducts',
    setLoggedInUsersAccount = 'setLoggedInUsersAccount',
    setLoggedInUser = 'setLoggedInUser',
    setCaseLanguages = 'setCaseLanguages',
    setCaseGroups = 'setCaseGroups',
    setPcmConfig = 'setPcmConfig',
    setLoggedInUserJwtToken = 'setLoggedInUserJwtToken',
    setRecommendationDocsTrack = 'setRecommendationDocsTrack',
    setSearchTrackingData = 'setSearchTrackingData',
    setGuid = 'setGuid',
    receivedGuid = 'receivedGuid',
    setTrackingProductFlag = 'setTrackingProductFlag',
    setRef = 'setRef'
}
const initialProductResponse = {
    topProducts: [],
    otherProducts: [],
    productsResult: []
};

export const initialAppMetadataState: IAppMetadataState = {
    allCaseTypes: CaseUtils.getApiResourceObject([]),
    allCaseSeverities: CaseUtils.getApiResourceObject([]),
    allCaseEntitlements: CaseUtils.getApiResourceObject([]),
    allProducts: CaseUtils.getApiResourceObject(initialProductResponse),
    loggedInUsersAccount: CaseUtils.getApiResourceObject({}),
    loggedInUser: CaseUtils.getApiResourceObject({}),
    loggedInUserJwtToken: {},
    caseLanguages: CaseUtils.getApiResourceObject([]),
    caseGroups: CaseUtils.getApiResourceObject([]),
    guid: CaseUtils.getApiResourceObject(''),
    trackingProductFlag: false,
    pcmConfig: CaseUtils.getApiResourceObject([]),
    nextButtonRef: null
};

// Resucers
export const appMetadataReducer = (pState: IAppMetadataState, action: IActionType): IAppMetadataState => {
    switch (action.type) {
        case AppMetadataReducerConstants.setCaseTypes: {
            return { ...pState, allCaseTypes: action.payload.allCaseTypes };
        }
        case AppMetadataReducerConstants.setCaseSeverities: {
            return { ...pState, allCaseSeverities: action.payload.allCaseSeverities };
        }
        case AppMetadataReducerConstants.setCaseEntitlements: {
            return { ...pState, allCaseEntitlements: action.payload.allCaseEntitlements };
        }
        case AppMetadataReducerConstants.setAllProducts: {
            return { ...pState, allProducts: action.payload.allProducts };
        }
        case AppMetadataReducerConstants.setLoggedInUsersAccount: {
            return { ...pState, loggedInUsersAccount: action.payload.loggedInUsersAccount };
        }
        case AppMetadataReducerConstants.setLoggedInUser: {
            return { ...pState, loggedInUser: action.payload.loggedInUser };
        }
        case AppMetadataReducerConstants.setCaseLanguages: {
            return { ...pState, caseLanguages: action.payload.caseLanguages };
        }
        case AppMetadataReducerConstants.setCaseGroups: {
            return { ...pState, caseGroups: action.payload.caseGroups };
        }
        case AppMetadataReducerConstants.setPcmConfig: {
            return { ...pState, pcmConfig: action.payload.pcmConfig };
        }
        case AppMetadataReducerConstants.setLoggedInUserJwtToken: {
            return { ...pState, loggedInUserJwtToken: action.payload.loggedInUserJwtToken };
        }
        case AppMetadataReducerConstants.setGuid: {
            return { ...pState, guid: action.payload.guid };
        }
        case AppMetadataReducerConstants.setTrackingProductFlag: {
            return { ...pState, trackingProductFlag: true };
        }
        case AppMetadataReducerConstants.setRef: {
            return { ...pState, nextButtonRef: action.payload.nextButtonRef };
        }
        default: {
            return pState;
        }
    }
};

// Actions
export const fetchCaseTypes = async (dispatch: AppMetadataReducerDispatchType) => {
    dispatch({ type: AppMetadataReducerConstants.setCaseTypes, payload: { allCaseTypes: CaseUtils.getApiResourceObject([], true) } });
    try {
        const caseTypes = await getCaseTypes();
        dispatch({ type: AppMetadataReducerConstants.setCaseTypes, payload: { allCaseTypes: CaseUtils.getApiResourceObject(caseTypes.value) } });
    } catch (e) {
        dispatch({ type: AppMetadataReducerConstants.setCaseTypes, payload: { allCaseTypes: CaseUtils.getApiResourceObject([], false, true, e.message) } });
    }
};
export const fetchCaseSeverities = async (dispatch: AppMetadataReducerDispatchType) => {
    dispatch({ type: AppMetadataReducerConstants.setCaseSeverities, payload: { allCaseSeverities: CaseUtils.getApiResourceObject([], true) } });
    try {
        const severities = await getSeverities();
        const allCaseSeverities = orderBy(severities.value, 'name', 'desc');
        dispatch({ type: AppMetadataReducerConstants.setCaseSeverities, payload: { allCaseSeverities: CaseUtils.getApiResourceObject(allCaseSeverities) } });
    } catch (e) {
        dispatch({ type: AppMetadataReducerConstants.setCaseSeverities, payload: { allCaseSeverities: CaseUtils.getApiResourceObject([], false, true, e.message) } });
    }
};
export const fetchCaseEntitlements = async (dispatch: AppMetadataReducerDispatchType, token: Partial<IPortalJwtToken>) => {
    dispatch({ type: AppMetadataReducerConstants.setCaseEntitlements, payload: { allCaseEntitlements: CaseUtils.getApiResourceObject([], true) } });
    try {
        const caseEntitlements = await getEntitelmentsForContact(token.username);
        dispatch({ type: AppMetadataReducerConstants.setCaseEntitlements, payload: { allCaseEntitlements: CaseUtils.getApiResourceObject(getProcessedEntitlements(caseEntitlements.entitlement)) } });
    } catch (e) {
        dispatch({ type: AppMetadataReducerConstants.setCaseEntitlements, payload: { allCaseEntitlements: CaseUtils.getApiResourceObject([], false, true, e.message) } });
    }
};
export const fetchProducts = async (dispatch: AppMetadataReducerDispatchType) => {
    try {
        dispatch({ type: AppMetadataReducerConstants.setAllProducts, payload: { allProducts: CaseUtils.getApiResourceObject(initialProductResponse, true) } });
        const responseString = await getSEProductsList();
        const response: string[][] = JSON.parse(responseString);
        const allProducts = handleProductSearchResponse(response);
        dispatch({ type: AppMetadataReducerConstants.setAllProducts, payload: { allProducts: CaseUtils.getApiResourceObject(allProducts) } });
    } catch (e) {
        dispatch({ type: AppMetadataReducerConstants.setAllProducts, payload: { allProducts: CaseUtils.getApiResourceObject(initialProductResponse, false, true, e.message) } });
    }
};
export const setAllProducts = (dispatch: AppMetadataReducerDispatchType, allProducts: IProductResponse) => {
    dispatch({ type: AppMetadataReducerConstants.setAllProducts, payload: { allProducts: CaseUtils.getApiResourceObject(allProducts) } });
};
export const fetchLoggedInUsersAccount = async (dispatch: AppMetadataReducerDispatchType, token: Partial<IPortalJwtToken>) => {
    try {
        dispatch({ type: AppMetadataReducerConstants.setLoggedInUsersAccount, payload: { loggedInUsersAccount: CaseUtils.getApiResourceObject({}, true) } });
        let accountNumber = token.account_number;
        //  Get account number from SFDC if token doesn't have it
        if (isEmpty(accountNumber)) {
            accountNumber = await getAccountDetails() as string;
            setLoggedInUserJwtToken(dispatch, {...token, account_number: accountNumber});
            setStrataHeaders('Solution Engine', get(window, 'seVersionInfo.gitTag'), accountNumber);
        }
        const loggedInUsersAccount = await getAccountDetails(accountNumber) as IStrataAccountResponse;
        dispatch({ type: AppMetadataReducerConstants.setLoggedInUsersAccount, payload: { loggedInUsersAccount: CaseUtils.getApiResourceObject(loggedInUsersAccount) } });
    } catch (e) {
        dispatch({ type: AppMetadataReducerConstants.setLoggedInUsersAccount, payload: { loggedInUsersAccount: CaseUtils.getApiResourceObject({}, false, true, e.message) } });
    }
};
export const fetchLoggedInUser = async (dispatch: AppMetadataReducerDispatchType, token: Partial<IPortalJwtToken>) => {
    try {
        dispatch({ type: AppMetadataReducerConstants.setLoggedInUser, payload: { loggedInUser: CaseUtils.getApiResourceObject({}, true) } });
        const loggedInUser = await getStrataUser(token.user_id);
        dispatch({ type: AppMetadataReducerConstants.setLoggedInUser, payload: { loggedInUser: CaseUtils.getApiResourceObject(loggedInUser) } });
    } catch (e) {
        dispatch({ type: AppMetadataReducerConstants.setLoggedInUser, payload: { loggedInUser: CaseUtils.getApiResourceObject({}, false, true, e.message) } });
    }
};
export const fetchLanguageMetadata = async (dispatch: AppMetadataReducerDispatchType) => {
    try {
        dispatch({ type: AppMetadataReducerConstants.setCaseLanguages, payload: { caseLanguages: CaseUtils.getApiResourceObject([], true) } });
        const response = await hydrajs.kase.metadata.getLanguagesMetadata();
        dispatch({ type: AppMetadataReducerConstants.setCaseLanguages, payload: { caseLanguages: CaseUtils.getApiResourceObject(response.items) } });
    } catch (e) {
        dispatch({ type: AppMetadataReducerConstants.setCaseLanguages, payload: { caseLanguages: CaseUtils.getApiResourceObject([], false, true, e.message) } });
    }
};
export const fetchCaseGroupsForSSO = async (dispatch: AppMetadataReducerDispatchType, token: Partial<IPortalJwtToken>) => {
    try {
        dispatch({ type: AppMetadataReducerConstants.setCaseGroups, payload: { caseGroups: CaseUtils.getApiResourceObject([], true) } });
        const response = await getCaseGroupsForSSO(token.username);
        dispatch({ type: AppMetadataReducerConstants.setCaseGroups, payload: { caseGroups: CaseUtils.getApiResourceObject(response.group, true) } });
    } catch (e) {
        dispatch({ type: AppMetadataReducerConstants.setCaseGroups, payload: { caseGroups: CaseUtils.getApiResourceObject([], false, true, e.message) } });
    }
};
export const setLoggedInUserJwtToken = (dispatch: AppMetadataReducerDispatchType, loggedInUserJwtToken: Partial<IPortalJwtToken>) => {
    dispatch({ type: AppMetadataReducerConstants.setLoggedInUserJwtToken, payload: { loggedInUserJwtToken } });
};
export const getSerchTrackingGuid = async (dispatch: AppMetadataReducerDispatchType) => {
    try {
        dispatch({ type: AppMetadataReducerConstants.setGuid, payload: { guid: CaseUtils.getApiResourceObject('', true) } });
        const guidObj = await getGuid();
        dispatch({ type: AppMetadataReducerConstants.setGuid, payload: { guid: CaseUtils.getApiResourceObject(JSON.parse(guidObj).guid) } });
    } catch (e) {
        dispatch({ type: AppMetadataReducerConstants.setGuid, payload: { guid: CaseUtils.getApiResourceObject('', false, true, e.message) } });
        // tslint:disable-next-line:no-console
        console.log('tracking api failed');
    }
};
export const setTrackingProductFlag = (dispatch: AppMetadataReducerDispatchType) => {
    dispatch({ type: AppMetadataReducerConstants.setTrackingProductFlag });
};
export const loadPCMConfig = async (dispatch: AppMetadataReducerDispatchType) => {
    try {
        dispatch({ type: AppMetadataReducerConstants.setPcmConfig, payload: { pcmConfig: CaseUtils.getApiResourceObject([], true) } });
        const pcmConfig = await hydrajs.maintenance.getMaintenanceMode('pcm_configurations' as any) || [];
        dispatch({ type: AppMetadataReducerConstants.setPcmConfig, payload: { pcmConfig: CaseUtils.getApiResourceObject(pcmConfig) } });
    } catch (e) {
        dispatch({ type: AppMetadataReducerConstants.setPcmConfig, payload: { pcmConfig: CaseUtils.getApiResourceObject([], false, true, e.message) } });
    }
};
export const setRef = (dispatch: AppMetadataReducerDispatchType, nextButtonRef: React.MutableRefObject<HTMLButtonElement>) => {
    nextButtonRef && dispatch({ type: AppMetadataReducerConstants.setRef, payload: { nextButtonRef } });
};
