// Setup basic express server
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
const { sendFirebaseNotification } = require('./Utils/notification');
var port = process.env.DB_PORT || 4005;
var DB_HOST = process.env.DB_HOST || '127.0.0.1';
var DB_USER = process.env.DB_USERNAME || 'root';
var DB_PASSWORD = process.env.DB_PASSWORD || 'Kmphitech@123Voice';
var DB_NAME = process.env.DB_DATABASE || "voicebuddy";

// var DB_USER = process.env.DB_USERNAME || 'root';
// var DB_PASSWORD = process.env.DB_PASSWORD || '';
// var DB_NAME = process.env.DB_DATABASE || "voice_buddies";

const DB_CONNECTION_LIMIT = 2;

global.voicePath = "https://api.voicebuddies.net/voice_buddies/public/voices";
global.mediaPath = "https://api.voicebuddies.net/voice_buddies/public/chat";
// global.voicePath = "http://localhost/voice_buddies/public/voices";
// global.mediaPath = "http://localhost/voice_buddies/public/chat";
server.listen(port, () => {
    console.log('Server listening at port %d', port);
});

var mysql = require("mysql");
const utf8 = require('utf8');

var databasedsn = {
    host: DB_HOST,
    user: DB_USER,
    password: DB_PASSWORD,
    database: DB_NAME,
    connectionLimit: DB_CONNECTION_LIMIT,
    debug: false
};
var conn = mysql.createConnection(databasedsn);

conn.connect(async function (err) {
    if (err) throw err;
    console.log("Connected!");
})

async function executeComQuery(sqlQuery) {
    if (conn.state === 'disconnected') {
        conn = mysql.createConnection(databasedsn);
    }

    var resultsData = [];
    const result = new Promise((resolve, reject) => {
        conn.query(`${sqlQuery}`, (err, res) => {
            if (err) {
                console.log(sqlQuery);
                return reject("error sql query:-->>", `${err.message}`);
            }
            resultsData = res;
            resolve();
        });
    });
    await result;
    return resultsData;
}

async function executeQuery(sqlQuery) {

    if (conn.state === 'disconnected') {
        conn = mysql.createConnection(databasedsn);
    }

    var resultsData = [];
    const result = new Promise((resolve, reject) => {
        conn.query(`${sqlQuery}`, (err, res) => {
            if (err) {
                console.log(sqlQuery);
                return reject("error sql query:-->>", `${err.message}`);
            }
            resultsData = res;
            resolve();
        });
    });
    await result;
    return resultsData;
}

async function saveMessage(socket, message,senderId, receiverId, CreatedAt, msgType) {
    // console.log("message:"+message,"senderId:"+senderId, "receiverId:"+receiverId, "CreatedAt:"+CreatedAt, "msgType:"+msgType);
    message = utf8.encode(message);

    var sql = "INSERT INTO message_master (msg_type,sender_id,receiver_id,msg,created_at,updated_at) VALUE ('"+msgType+"','" + senderId + "','" + receiverId + "','" + message + "','" + CreatedAt + "','" + CreatedAt + "')";

    var result = await executeQuery(sql);
    var msgId = result.insertId;
    // console.log('test:'+msgId);
    if(senderId < receiverId){
        var roomId = senderId + "_" + receiverId;
    }else{
        var roomId = receiverId + "_" + senderId;
    }
    // console.log('saveMessage: room_id: '+roomId);
    emitEventFromAPI(socket, msgId, receiverId , roomId);
}

async function getRoomId(loginId, receiverId){
    var room = ''
    if(loginId < receiverId){
        room = loginId + "_" + receiverId;
    }else{
        room = receiverId + "_" + loginId;
    }
    
    return room;
}

async function emitEventFromAPI(socket, msgId, receiverId , roomId) {
    // console.log(roomId);
    // console.log(socket.rooms);
    var sqls = "SELECT CAST(mm.msg_id as CHAR(50)) as msg_id,mm.msg,mm.msg_type,CAST(mm.sender_id as CHAR(50)) as sender_id,CAST(mm.receiver_id as CHAR(50)) as receiver_id,DATE_FORMAT(mm.created_at,'%Y-%m-%d %H:%i:%s') AS created_at,um.device_token FROM message_master mm JOIN user_master um ON um.user_id = mm.receiver_id WHERE mm.msg_id='" + msgId + "'";
    var newMsg = await executeQuery(sqls);
    
    newMsg[0].msg = global.mediaPath+'/'+utf8.decode(newMsg[0].msg);
    var notifyMsg = 'Sent a audio';
    
    // console.log(roomId);
    socket.to(roomId).emit('setNewMessage', {
        resData: newMsg[0]
    });

    var Listsql = "SELECT CAST(m1.msg_id as CHAR(50)) as msg_id,m1.msg,CAST(m1.sender_id as CHAR(50)) as sender_id,CAST(m1.receiver_id as CHAR(50)) as receiver_id,m1.msg_type, DATE_FORMAT(m1.created_at,'%Y-%m-%d %H:%i:%s') AS created_at,CAST(um.user_id as CHAR(50)) as user_id,um.fname,um.is_delete,um.unique_id,(SELECT CAST(IFNULL(COUNT(*),0) as CHAR(50)) FROM message_master WHERE receiver_id='" + receiverId + "' AND sender_id=m1.sender_id AND is_read=0 GROUP BY receiver_id) as unread_count,IF((m1.sender_id = " + receiverId + "),m1.receiver_id,m1.sender_id) as other_id,IF((um.voice != ''),concat('" + global.voicePath + "/', um.voice),'') as profile FROM `message_master` as m1 LEFT JOIN user_master as um ON IF((m1.sender_id = " + receiverId + "),m1.receiver_id,m1.sender_id) = um.user_id WHERE (m1.sender_id = " + receiverId + " OR m1.receiver_id = " + receiverId + ") AND (msg_id IN( SELECT MAX(m2.msg_id) FROM message_master m2 WHERE (m2.sender_id = " + receiverId + ") OR (m2.receiver_id = " + receiverId + ") GROUP BY ( IF( m2.sender_id = " + receiverId + ", m2.receiver_id, m2.sender_id ) ) ) ) AND um.user_id IS NOT NULL GROUP BY other_id ORDER BY m1.created_at DESC";
    var updatedlistUser = await executeQuery(Listsql);

    var chatList = updatedlistUser[0];

    chatList.msg = utf8.decode(chatList.msg);
    chatList.msg = global.mediaPath+'/'+utf8.decode(chatList.msg);
    socket.to(receiverId.toString()).emit('updateChatList', {
        resData: chatList
    });

    let receiverToken = newMsg[0].device_token;

    if (receiverToken && receiverToken != "") {
        let notiData = { notification_type: "message", type: "chat" }
        await sendFirebaseNotification(receiverToken, "", notifyMsg, notiData);
    }
}


io.on('connection', (socket) => {

    socket.on('getChatUserList', async (loginId) => {
        var sql = "SELECT CAST(m1.msg_id as CHAR(50)) as msg_id,m1.msg,CAST(m1.sender_id as CHAR(50)) as sender_id,CAST(m1.receiver_id as CHAR(50)) as receiver_id,m1.msg_type, DATE_FORMAT(m1.created_at,'%Y-%m-%d %H:%i:%s') AS created_at,CAST(um.user_id as CHAR(50)) as user_id,um.fname,um.is_delete,um.unique_id ,(SELECT CAST(IFNULL(COUNT(*),0) as CHAR(50)) FROM message_master WHERE receiver_id='" + loginId + "' AND sender_id=m1.sender_id AND is_read=0 GROUP BY receiver_id) as unread_count,IF((m1.sender_id = " + loginId + "),m1.receiver_id,m1.sender_id) as other_id, IF((um.voice != ''),concat('" + global.voicePath + "/', um.voice),'') as profile FROM `message_master` as m1 LEFT JOIN user_master as um ON IF((m1.sender_id = " + loginId + "),m1.receiver_id,m1.sender_id) = um.user_id WHERE (m1.sender_id = " + loginId + " OR m1.receiver_id = " + loginId + ") AND (msg_id IN( SELECT MAX(m2.msg_id) FROM message_master m2 WHERE (m2.sender_id = " + loginId + ") OR (m2.receiver_id = " + loginId + ") GROUP BY ( IF( m2.sender_id = " + loginId + ", m2.receiver_id, m2.sender_id ) ) ) ) AND um.user_id IS NOT NULL GROUP BY other_id ORDER BY m1.created_at DESC";
        var result = await executeQuery(sql);
        socket.join(loginId.toString());
        var chatList = result;
        var blockUserList = await executeQuery("SELECT user_to from block_master where user_by="+loginId)
        blockUserList  = blockUserList.map((row)=>{
           return row.user_to
        })
        console.log(blockUserList);
        chatList = chatList.map((data) => {
            if(! blockUserList.includes(+data.user_id)){
                data.msg = global.mediaPath+'/'+utf8.decode(data.msg);
                data.msg_id = (data.msg_id) ? data.msg_id : "";
                data.sender_id = (data.sender_id) ? data.sender_id : "";
                data.receiver_id = (data.receiver_id) ? data.receiver_id : "";
                data.msg_type = (data.msg_type) ? data.msg_type : "";
                data.created_at = (data.created_at) ? data.created_at : "";
                data.unread_count = (data.unread_count) ? data.unread_count : "0";
                return data;
            }else{
                return '';
            }
            
        });
        var chatListArr = []
        chatList.forEach(function (i){
            if(i!=''){
                chatListArr.push(i);
            }
        })

        socket.emit('setChatUserList', {
            resData: chatListArr
        });

    });

    socket.on('getMessageList', async (loginId, receiverId) => {
        var sql = "SELECT CAST(mm.msg_id as CHAR(50)) as msg_id,mm.msg,mm.msg_type, CAST(mm.sender_id as CHAR(50)) as sender_id,CAST(mm.receiver_id as CHAR(50)) as receiver_id,DATE_FORMAT(mm.created_at,'%Y-%m-%d %H:%i:%s') AS created_at FROM message_master mm WHERE (mm.sender_id='" + receiverId + "' AND mm.receiver_id='" + loginId + "') OR (mm.sender_id='" + loginId + "' AND mm.receiver_id='" + receiverId + "') ORDER BY mm.msg_id DESC";
        console.log("sql=>",sql)

        var result = await executeQuery(sql);
        var roomId = await getRoomId(loginId, receiverId);
        // console.log("getMessageList: roomId: "+roomId);
        socket.join(roomId);
        console.log("result=>",result)
        var MsgList = await Promise.all(
            result.map(async(data) => {
                data.msg = global.mediaPath+'/'+utf8.decode(data.msg);
                return data;
            })
        );
        console.log("messageList=>",MsgList)
        var updSQL = "UPDATE message_master SET is_read = 1 WHERE receiver_id=" + loginId + " AND sender_id="+receiverId;
        var results = await executeQuery(updSQL);
        socket.emit('setMessageList', {
            resData: MsgList
        });
    });

    socket.on('sendMessage', async (message,senderId, receiverId, CreatedAt, msgType='audio') => {
        await saveMessage(socket, message,senderId, receiverId, CreatedAt, msgType);
    });
    
    socket.on('disconnect', () => {
        console.log("socket disconnected");
    });
});
