import { NetworkProxy } from "../drivers/network/typings";
import { ISenderRepository } from "./CfSender";
import { Event } from "./typings";
import { v4 as uuidv4 } from 'uuid';

interface QueueItem {
    uuid: string;
    event: any;
    url: string;
    time: number;
    retries: number;
    lastRetry?: number;
}

interface NetworkQueueOptions {
    flushInterval?: number;
    maxRetries?: number
}

class CfNetworkQueue implements NetworkProxy{
    private bsNetwork
    private options: NetworkQueueOptions
    private queue: QueueItem[]
    private flushIntervalId

    constructor(bsNetwork: NetworkProxy, options?: NetworkQueueOptions) {
        this.bsNetwork = bsNetwork
        this.queue = []
        const defaultOptions = {
            flushInterval: 10*1000,
            maxRetries: 10
        }

        this.options = {...defaultOptions, ...options}

        this.flushIntervalId = +setInterval(() => {
            this.flush()
        }, this.options.flushInterval)
    }


    private removeFromQueue(uuid) {
        this.queue = this.queue.filter(item => item.uuid !== uuid)
    }

    private removeQueueItemsExceedMaxRetries() {
        this.queue = this.queue.filter(item => item.retries <= this.options.maxRetries)
    }

    private itemInQueue(uuid):boolean {
        return this.queue.find(queueItem => queueItem.uuid === uuid) !== undefined
    }

    private flush() {
        this.queue.forEach(item => this.sendToNetwork(item))
    }

    private sendToNetwork(item: QueueItem): void {
        this.bsNetwork.send(item.url, item.event)
            .then(() => {
                this.removeFromQueue(item.uuid)
            })
            .catch(() => {
                if (this.itemInQueue(item.uuid)) {
                    const thisItemInQueue = this.queue.find(queueItem => queueItem.uuid === item.uuid)
                    thisItemInQueue.retries++

                } else {
                    this.queue.push(item)
                }

            })
            .finally(() => {
                this.removeQueueItemsExceedMaxRetries()
            })
    }

    send(url: string, data: any): void {
        const item: QueueItem = {
            uuid: uuidv4(),
            event: data,
            url,
            time: +new Date(),
            retries: 0
        }
        this.sendToNetwork(item)
    }

    get(url: string): Promise<Object> {
        throw new Error("Method not implemented.");
    }

}

export default CfNetworkQueue

