
import {SQS} from 'aws-sdk';
import * as sqsConsumer from "sqs-consumer";
import {Options} from "sqs-consumer";
import {MortarPlugin, MortarPluginDataEvent, Contract} from "@pythagoras/ts-pipeline";

export class SQSMortarPlugin extends MortarPlugin {

    private consumer: sqsConsumer.Consumer;

    private queue: SQS;
    private url: string;
    private region: string;

    constructor() {
        super();
    }

    public initialize(sqs: SQS, url: string, region:string): void {
        this.queue = sqs;
        this.url = url;
        this.region = region;
        this.initializeConsumer();
    }

    private initializeConsumer(): boolean {
        this.consumer = sqsConsumer.create(<Options>{
            queueUrl: this.url,
            region: this.region,
            sqs: this.queue,
            messageAttributeNames: [],
            handleMessage: this.handleSQSmessage.bind(this),
        });

        this.consumer.on('processing_error', (error: Error, message: SQS.Message) => {
            console.log(error.message);
        });

        return true;
    }

    private handleSQSmessage(message: SQS.Message, done: Function): void {
        let contract: object;
        try {
            contract = JSON.parse(message.Body);
        } catch (err) {
            done(new Error('Unable to parse body.'));
        }

        this.emit('data', <MortarPluginDataEvent>{
            contract: contract,
            callback: done,
        });
        done();
    }

    private sendSQSMessage(message: object): Promise<boolean> {
        let params = {
            MessageBody: JSON.stringify(message),
            QueueUrl: this.url,
            MessageAttributes: {},
        };
        return new Promise((resolve, reject) => {
            this.queue.sendMessage(params, (err, data) => {
                if (err) {
                    reject(err);
                }
                resolve(true);
            });
        });
    }


    write<A extends Contract>(chunk: A): Promise<boolean> {
        return this.sendSQSMessage(chunk)
            .then(result => {
                return true;
            })
            .catch(error => {
                //TODO: handle Errors
            });
    }


    resume(): void {
        this.consumer.start();
    }

    pause(): void {
        this.consumer.stop();
    }
}