
import Redis from 'ioredis'
import { type } from 'os'
const unflatten = require('flat').unflatten
var flatten = require('flat')
import ListContactsServiceCache from "../services/ContactServices/ListContactsServiceCache"
import { redisConn } from './TicketCache'


const deleteContactsByIdCache = async (id: string | number) => {

    const redis: any = await redisConn();

    if (!redis) return

   //  if (redis.status !== 'connect') return

    const contact_cache: any = await redis.hgetall(`contact:${id}`)

    try {
        if (contact_cache && Object.keys(contact_cache).length > 0) {

            await redis.del(`contact:${id}`)

            console.log(`Contacts cache number ${contact_cache['number']} deleted!`)
        }
        else {
            console.log('CONTACT CACHE NOT FOUND!')
        }
    } catch (error) {
        console.log(`There was an error on deleteContactsByIdCache:  ${error}`)
    }

    // await redis.quit()
}

const updateContactCache = async (hash: any, json_object: any) => {

    const redis: any = await redisConn();

    if (!redis) return

   //  if (redis.status !== 'connect') return

    const pipeline = redis.pipeline()

    let entries = Object.entries(json_object)

    entries.forEach((e: any) => {
        pipeline.hset(hash, e[0], e[1])
    })

    await pipeline.exec(() => { console.log("Key/value inserted/updated") });

    // await redis.quit()

}

const updateContactCacheById = async (id: string | number, update_fields: object | any) => {

    const redis: any = await redisConn();

    if (!redis) return

   //  if (redis.status !== 'connect') return

    const contact_cache: any = await redis.hgetall(`contact:${id}`)

    try {
        if (contact_cache && Object.keys(contact_cache).length > 0) {

            // await redis.del(`contact:${id}`) 

            update_fields.escaped_name = escapeCharCache(update_fields.name)

            await updateContactCache(`contact:${id}`, update_fields)

            console.log(`CONTACT ${contact_cache['number']} CACHE WAS UPDATED!`)
        }
        else {
            console.log('CONTACT CACHE NOT FOUND!')
        }
    } catch (error) {
        console.log(`There was an error on updateContactCacheById:  ${error}`)
    }

    // await redis.quit()
}

const createOrUpdateContactCache = async (hash: any, contact: any) => {

    const redis: any = await redisConn();

    if (!redis) return

   //  if (redis.status !== 'connect') return

    if (contact.name) {
        contact.escaped_name = escapeCharCache(contact.name)
    }

    await redis.hmset(hash, contact);

    // await redis.quit()

}


async function searchContactCache(search: string, offset: number, limit: number) {

    const redis: any = await redisConn();

    if (!redis) return

   //  if (redis.status !== 'connect') return null

    search = escapeCharCache(search)

    const response: any = await redis.call('FT.SEARCH', 'idx_contact_message', `(@escaped_name:*${search}*)|(@number:*${search}*)`, 'LIMIT', offset, limit, 'SORTBY', 'escaped_name', 'ASC')
    // await redis.quit()


    if (response.length === 1) {
        return []
    }

    const results: any = []

    for (let n = 2; n < response.length; n += 2) {
        const result: any = {}
        const fieldNamesAndValues = response[n]

        for (let m = 0; m < fieldNamesAndValues.length; m += 2) {
            const k = fieldNamesAndValues[m]
            const v = fieldNamesAndValues[m + 1]
            result[k] = v
        }

        results.push(result)
    }

    return results
}


const removeExtraSpace = (str: string) => {

    str = str.replace(/^\s+/g, '')

    return str.replace(/\s+/g, ' ')
}

const escapeCharCache = (str: string) => {

    const pattern = /[\'|\"|\.|\,|\;|\<|\>|\{|\}|\[|\]|\"|\'|\=|\~|\*|\:|\#|\+|\^|\$|\@|\%|\!|\&|\)|\(|/|\-|\\)]/g; // no match, use replace function.

    let newStr = str.replace(pattern, (t1) => `\\${t1}`);

    newStr = removeExtraSpace(newStr)

    return newStr.trim()

}

const getLastId = async (hash: any) => {

    const redis: any = await redisConn();

    if (!redis) return

   //  if (redis.status !== 'connect') return

    const contact_cache: any = await redis.hgetall(hash) 

    return contact_cache

}

const insertMessageContactCache = async (hash: any, contact_message: any) => {

    const redis: any = await redisConn();

    if (!redis) return

   //  if (redis.status !== 'connect') return

    await redis.hmset(hash, contact_message);

    console.log('CREATED/UPDATED CONTACT MESSAGE')

    // await redis.quit()

}

const loadContactsCache = async () => {

    await createContactMessageIndexCache('idx_contact_message')

    const redis: any = await redisConn();

    if (!redis) return

   //  if (redis.status !== 'connect') return

    let contacts = await ListContactsServiceCache()

    const pipeline = redis.pipeline()

    for (let i = 0; i < contacts.length; i++) {

        contacts[i].createdAt = new Date(contacts[i].createdAt).toISOString()
        contacts[i].updatedAt = new Date(contacts[i].updatedAt).toISOString()

        contacts[i].escaped_name = escapeCharCache(contacts[i].name)

        pipeline.hmset(`contact:${contacts[i].id}`, contacts[i]);
    }

    await pipeline.exec(() => { console.log(`${contacts.length} CONTACTS INSERTED IN CACHE!`) });

    // await redis.quit()
}

const createContactMessageIndexCache = async (hashIndex: string) => {

    const redis: any = await redisConn();

    if (!redis) return

   //  if (redis.status !== 'connect') return

    try {

        const lst_index_redis: any = await redis.call('FT._LIST')

        if (lst_index_redis.includes(hashIndex)) {
            console.log('entrou...')
            await redis.call('FT.DROPINDEX', hashIndex)
        }

        const response = await redis.call('FT.CREATE', hashIndex, 'ON', 'HASH', 'PREFIX', '1', 'contact_message:', 'SCHEMA', 'number', 'TEXT', 'SORTABLE')

        console.log('contact_message index created: ', response)

    } catch (error) {
        console.log('There was an error on contact_message: ', error)
    }

    // await redis.quit()
}

export {
    loadContactsCache,
    searchContactCache,
    deleteContactsByIdCache,
    updateContactCacheById,
    createOrUpdateContactCache,
    escapeCharCache,

    insertMessageContactCache,
    getLastId
}