import dotenv from "dotenv";
import DB from "../../config/database/db";
import {
    redisSubscriber,
    REDIS_CHANNEL
} from "../../config/redis/redis";

import {
    getPendingMessages,
    claimMessage,
    resetMessage,
    failedMessage,
    moveToSent
} from "./model/whatsappMessage.model";

import {
    sendWhatsappMessage
} from "./service/whatsapp";

import { whatsappLog } from "../serviceLog";

dotenv.config();

let isProcessing = false;
let signalReceived = false;
let shuttingDown = false;

async function processMessage(message: any) {

    const claimed = await claimMessage(message.id);

    if (!claimed) {
        whatsappLog.info(
            `Message Id ${message.id} already processed by another worker`
        );

        return;
    }
    let response: any;
    try {

        // whatsappLog.info(
        //     `Processing WhatsApp message ID: ${message.id}`
        // );

        response = await sendWhatsappMessage(message);

        if (!response.status) {
            throw new Error(
                `Message [${message.id}] failed to send`
            );
        }

        await moveToSent(
            message,
            response.message || ""
        );

        whatsappLog.info(
            `Message [${message.id}] sent successfully`
        );

    } catch (error) {

        whatsappLog.info(
            `WhatsApp message [${message.id}] failed`,
            error
        );

        await failedMessage(message.id);
        if(response.message == 'Not a valid number') {
            await moveToSent(
                message,
                response.message || ""
            );
        }
    }
}

async function processPendingMessages() {

    while (!shuttingDown) {

        const messages = await getPendingMessages();

        if (messages.length === 0) {
            return;
        }

        whatsappLog.info(
            `New Messages ${messages.length}`
        );

        for (const message of messages) {

            if (shuttingDown) {
                return;
            }

            await processMessage(message);
        }
    }
}

async function processQueue() {

    if (isProcessing) {
        return;
    }

    isProcessing = true;

    try {

        do {

            signalReceived = false;

            await processPendingMessages();

        } while (signalReceived && !shuttingDown);

    } catch (error) {

        whatsappLog.info(
            "WhatsApp queue error:",
            error
        );

    } finally {

        isProcessing = false;
    }
}

async function start() {

    await redisSubscriber.connect();

    whatsappLog.info("Redis connected");

    await redisSubscriber.subscribe(
        REDIS_CHANNEL,
        async () => {

            whatsappLog.info(
                `Redis trigger received: ${REDIS_CHANNEL}`
            );

            signalReceived = true;

            if (!isProcessing) {
                await processQueue();
                whatsappLog.info(
                `Redis [${REDIS_CHANNEL}] waiting........`
            );
            }
            
        }
    );

    whatsappLog.info(
        `WhatsApp worker started. Listening: ${REDIS_CHANNEL}`
    );

    // Process any messages already present in the queue
    // when the worker starts
    if (!isProcessing) {
        whatsappLog.info("Checking existing WhatsApp queue...");
        await processQueue();
        whatsappLog.info(
                `Redis [${REDIS_CHANNEL}] waiting........`
            );
    }
}

async function shutdown() {

    if (shuttingDown) {
        return;
    }

    shuttingDown = true;

    whatsappLog.info("Stopping WhatsApp worker...");

    try {
        await redisSubscriber.unsubscribe(
            REDIS_CHANNEL
        );

        await redisSubscriber.quit();

    } catch (error) {

        whatsappLog.info(
            "Redis shutdown error:",
            error
        );
    }

    try {

        await DB.end();

    } catch (error) {

        whatsappLog.info(
            "Database shutdown error:",
            error
        );
    }

    process.exit(0);
}

process.on("SIGINT", shutdown);
process.on("SIGTERM", shutdown);

start().catch(async error => {

    whatsappLog.info(
        "Worker startup failed:",
        error
    );

    await shutdown();
});