import {INudgesRepository, Nudge, NudgeAction} from './repositories/nudges/typings'
import {EventEmitter} from 'events';
import {NotificationAction, NotificationDispatcher} from '../drivers/notifications/typings'
import {INudgeManager, NudgeManagerAction} from './CfNudgeManager.typings';
import Navigation from "../modules/Navigation/index";
import {NudgeScreenType} from "./commonTypes";

interface IndexedNudge {
    [key: string]: Nudge
}

export default class NudgeManager extends EventEmitter implements INudgeManager {
    private timersId = []
    private notificationDispatcher
    private nudgesRepository
    private refreshInterval = 5 * 60 * 1000
    private isOneTimeOnly = false
    private nudgeScreenType = NudgeScreenType.None
    private indexedNudges: IndexedNudge = {}

    public constructor(
        userId: string,
        notificationDispatcher: NotificationDispatcher,
        nudgesRepository: INudgesRepository,
        nudgeScreenType = NudgeScreenType.None,
        isOneTimeOnly = false,
        refreshInterval = 5 * 60 * 1000
    ) {
        super()
        this.notificationDispatcher = notificationDispatcher
        this.nudgesRepository = nudgesRepository
        this.refreshInterval = refreshInterval
        this.nudgeScreenType = nudgeScreenType
        this.isOneTimeOnly = isOneTimeOnly
        /*
           - nudges are retrieved periodically, each 5min.
           - in the future this timeout will be configurable
           - dispatched_at will be:
               - current time less 1 hour the first time
               - time of last shown nudge, if exists, or current time next times
        */

        this.notificationDispatcher.on(NotificationAction.Open, (nudge: Nudge) => {
            if (!nudge) {
                return
            }
            Navigation.logPushNotificationEvent({
                response: NudgeAction.Open,
                details: "",
                internal: nudge.internal
            })

            const hasActions = () => {
                return (!!nudge.attr?.cta_id)
            }

            if (!hasActions()) {
                return
            }
            const ctaObject = {
                type: nudge.attr?.cta_type.toLowerCase(),
                cta_resource: {
                    type:  "drug",
                    id: nudge.attr?.cta_id
                }
            }
            this.emit(
                NudgeManagerAction.Action,
                ctaObject)
        })

        this.notificationDispatcher.on(NotificationAction.Discard, (nudge: Nudge) => {
            if (!nudge) {
                return
            }
            Navigation.logPushNotificationEvent({
                response: NudgeAction.Discard,
                details: "",
                internal: nudge.internal
            })
        })

        this.notificationDispatcher.on(NotificationAction.Block, (nudge: Nudge) => {
            if (!nudge) {
                return
            }
            Navigation.logPushNotificationEvent({
                response: NudgeAction.Block,
                details: "",
                internal: nudge.internal
            })
        })

        this.notificationDispatcher.on(NotificationAction.Shown, (nudge: Nudge) => {
            if (!nudge) {
                return
            }
            Navigation.logPushNotificationEvent({
                response: NudgeAction.Shown,
                details: "",
                internal: nudge.internal
            })
        })

        // get nudge item:
        this.fetchNudges(userId, this.nudgeScreenType)

        if (!this.isOneTimeOnly) {
            setInterval(() => {
                this.fetchNudges(userId, this.nudgeScreenType)
            }, this.refreshInterval)
        }
    }

    private async fetchNudges(userId: string, nudgeScreenType: NudgeScreenType) {
        let nudges;

        try {
            nudges = await this.nudgesRepository.getNudges(userId, nudgeScreenType)
        } catch (e) {
            console.error('Error fetching nudges: ', e)
            return
        }
        nudges
            // .filter(({ ref }) => {
            //     const alreadyShown = this.nudgesRepository.haveBeenAlreadyShown(ref)
            //     return !alreadyShown
            // })
            .forEach((nudge, index) => {
                if (nudge.payload.error) {
                    Navigation.logPushNotificationEvent({
                        response: NudgeAction.Error,
                        details: nudge.payload.error,
                        internal: nudge.internal
                    });
                    return;
                } else {
                    this.indexedNudges[index] = nudge.payload
                    this.processNudge(nudge.payload)
                }
            })
    }

    private processNudge(nudge: Nudge) {
        if (!nudge.internal.expired_at) {
            nudge.internal.expired_at = "0001-01-01T00:00:00Z"
        }
        const expirationNotDefined = nudge.internal.expired_at === "0001-01-01T00:00:00Z"
        const notExpired = nudge.internal.expired_at > new Date().toISOString()
        if (notExpired || expirationNotDefined) {
            this.notificationDispatcher.show(nudge)
        } else {
            Navigation.logPushNotificationEvent({
                response: NudgeAction.Expired,
                details: "",
                internal: nudge.internal
            })
        }
    }

}
