import {injectEvent} from '../../core/injector'
import {hasRepeatedIds} from '../../utils'
import {ContentBlock} from '../Navigation/typings'
import {
    LevelProperties,
    LoyaltyTypes,
    MilestoneProperties,
    PromoProperties,
    RedeemType,
    RewardAction, RewardCatalog,
    RewardProperties, SurveyCatalog,
    SurveyProperties,
} from './typings'

import LoyaltyPropertiesTI from './typings-ti'
import {ICatalogRepository} from "../../core/repositories/catalog/CatalogRepository"
import CfExceptionHandler from "../../core/CfExceptionHandler";

const moduleName = ContentBlock.Loyalty

let catalogRepository: ICatalogRepository;

/**
 * Private function to inject repositories
 *
 * @ignore
 */
const init = (
    injectedCatalogRepository: ICatalogRepository
) => {
    catalogRepository = injectedCatalogRepository
}

const logPromoEvent = (properties: PromoProperties, sendNow = false) => {

    if(properties.id == ''){
        new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Promo, 'empty promo id')
    }else if(properties.title == ''){
        new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Promo, 'empty promo title')
    }else if(properties.action == undefined){
        new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Promo, 'invalid promo action')
    }else if (properties.items.length == 0) {
        new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Promo, 'empty promo items list')
    }else if (hasRepeatedIds(properties.items)) {
        new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Promo, 'promo items list repeated ids')
    }

    injectEvent(
        properties,
        [LoyaltyPropertiesTI],
        LoyaltyTypes.Promo,
        moduleName,
        '',
        sendNow)
}

const logLevelEvent = (properties: LevelProperties, sendNow = false) => {

    if(properties.module_id == ''){
        new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Level, 'empty level module id')
    }else if(properties.prev_level < 0){
        new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Level, 'negative level previous_level')
    }else if (properties.new_level < 0) {
        new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Level, 'negative level new_level')
    }

    injectEvent(properties, [LoyaltyPropertiesTI], LoyaltyTypes.Level, moduleName, '', sendNow)
}

const logMilestoneEvent = (properties: MilestoneProperties, sendNow = false) => {
    if(properties.id == ''){
        new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Milestone, 'empty milestone id')
    }else if(properties.action == undefined){
        new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Milestone, 'invalid milestone action')
    }
    injectEvent(properties, [LoyaltyPropertiesTI], LoyaltyTypes.Milestone, moduleName, '', sendNow)
}

const logSurveyEvent = (properties: SurveyProperties, sendNow = false) => {

    if (properties.action == undefined) {
        new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Survey, 'invalid survey action')
    } else if (properties.survey.id == '') {
        new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Survey, 'empty survey id')
    } else if (properties.survey.type == undefined) {
        new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Survey, 'invalid survey type')
    } else if (properties.survey.is_completed == undefined) {
        new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Survey, 'invalid survey is_completed')
    } else if (properties.response.length > 0) {
        for (const responseObject of properties.response) {
            if (responseObject.id == '') {
                new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Survey, 'empty survey response object id')
            } else if (responseObject.type == undefined) {
                new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Survey, 'invalid survey response object type')
            } else if (responseObject.question == '') {
                new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Survey, 'empty survey response object question')
            }
        }
    } else if (properties.response.length == 0) {
        new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Survey, 'empty survey response list')
    }

    injectEvent(properties,
        [LoyaltyPropertiesTI],
        LoyaltyTypes.Survey,
        moduleName, '', sendNow)
}

const logRewardEvent = async (properties: RewardProperties, sendNow = false) => {

    if (properties.id == '') {
        new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Reward, 'empty reward id')
    } else if (properties.action == undefined) {
        new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Reward, 'invalid reward action')
    } else if (properties.action == RewardAction.Add && properties.acc_points == undefined) {
        new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Reward, 'reward acc_points are required for add action')
    } else if (properties.total_points == undefined) {
        new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Reward, 'invalid reward total points')
    }else if (properties.action == RewardAction.Redeem && properties.acc_points == undefined) {
        new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Reward, 'reward redeem object required for redeem action')
    }else if (properties.action == RewardAction.Redeem && properties.redeem == undefined) {
        new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Reward, 'invalid reward redeem object')
    }else if (properties.action == RewardAction.Redeem && properties.redeem != undefined) {
        if (properties.redeem.type == undefined) {
            new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Reward, 'invalid reward redeem type')
        } else if (properties.redeem.is_successful == undefined) {
            new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Reward, 'invalid reward redeem is successful')
        } else if (properties.redeem.points_withdrawn == undefined) {
            new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Reward, 'invalid reward redeem points withdrawn')
        } else if (properties.redeem.converted_value == undefined) {
            new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Reward, 'invalid reward redeem converted value')
        } else if (properties.redeem.type == RedeemType.Cash && properties.redeem.currency == undefined) {
            new CfExceptionHandler().throwAndLogError(LoyaltyTypes.Reward, 'invalid reward currency')
        }
    }

    const internalRewardProperties = {
        ...properties,
    }

    injectEvent(internalRewardProperties,
        [LoyaltyPropertiesTI],
        LoyaltyTypes.Reward,
        moduleName, '', sendNow)
}


const logSurveyCatalog = (surveyId : string, properties: SurveyCatalog): void => {
    const surveyCatalog = "survey catalog"
    if(surveyId == ''){
        new CfExceptionHandler().throwAndLogError(surveyCatalog, 'empty survey catalog id')
    }else if(properties.name == ''){
        new CfExceptionHandler().throwAndLogError(surveyCatalog, 'empty survey catalog name')
    }else if(properties.type == undefined){
        new CfExceptionHandler().throwAndLogError(surveyCatalog, 'invalid survey catalog type')
    }else if(properties.reward_id == ''){
        new CfExceptionHandler().throwAndLogError(surveyCatalog, 'empty survey catalog reward id')
    }else if(properties.questions_list.length == 0){
        new CfExceptionHandler().throwAndLogError(surveyCatalog, 'empty survey catalog questions list')
    }
    catalogRepository.injectSurvey(surveyId, properties)
}

const logRewardCatalog = (rewardId : string, properties: RewardCatalog): void => {

    const rewardCatalog = "reward catalog"
    if(rewardId == ''){
        new CfExceptionHandler().throwAndLogError(rewardCatalog, 'empty reward catalog id')
    }else if(properties.name == ''){
        new CfExceptionHandler().throwAndLogError(rewardCatalog, 'empty reward catalog name')
    }else if(properties.type == undefined){
        new CfExceptionHandler().throwAndLogError(rewardCatalog, 'invalid reward catalog type')
    }else if(properties.required_points < 0){
        new CfExceptionHandler().throwAndLogError(rewardCatalog, 'negative reward catalog reward points')
    }

    catalogRepository.injectReward(rewardId, properties)
}

export default {
    logSurveyCatalog,
    logRewardCatalog,
    logLevelEvent,
    logMilestoneEvent,
    logPromoEvent,
    logSurveyEvent,
    logRewardEvent,
    init
}
