/* eslint-disable no-inner-declarations */
// -----------------------------------------------------------------
// CONFIG
// -----------------------------------------------------------------
// TODO: ep for these values
// js script to get from a single & multiple server & sum them

const cols = process.stdout.columns
// const rows = process.stdout.rows
const colWidth = 40
const maxStatLength = colWidth // Math.floor(cols / 4)
const statNameSpacing = 4
const beforeRowSpace = 13
const colsToPrint =
    Math.floor(cols / (colWidth + statNameSpacing + beforeRowSpace / 3 + 5)) ||
    1
const coloredWords = {
    red: ['lred', 'thanks'],
    cyan: [
        'getveteranpw',
        'pwrequest',
        'getpw',
        'availablepws',
        'login',
        'logout',
    ],
    green: [
        'manual',
        'todos',
        'allquestions',
        'subjectbrowser',
        'contribute',
        'feedback',
        'ranklist',
        'allqr',
        'possibleAnswers',
        'faq',
        '/script',
        'listUserDir',
        'forumEntries',
        'contacts.json',
        'patreon',
        'donate',
        'userfiles',
        'hasNewMsg',
    ],
    blue: [
        'isadding',
        'react',
        'ask',
        'newUserDir',
        'updateQuestion',
        'uploadUserFile',
        'votetodo',
        'registerscript',
        'install',
    ],
    magenta: [
        'addPost',
        'comment',
        'postfeedback',
        'quickvote',
        'getnewdatasince',
    ],
}
const filterFromDailyStats = [
    'savedQuestions',
    'sio/f',
    'sound/',
    '/img/',
    '.php',
    '/wordpress/',
    '/wp/',
    '/wp-includes/',
    'favicon',
    'robots.txt',
    'ads.txt',
    '/f/',
    '.git',
    'apple-touch-icon',
    '/.env',
    '/userFiles/',
    '.min.js',
    '.xml',
    '.aspx',
    '/questionDbs/',
    '/chatFiles/',
    'rss',
]

// -----------------------------------------------------------------

const fs = require('fs') // eslint-disable-line

const dir = process.argv[2]
const startDay =
    !isNaN(parseInt(process.argv[3])) && parseInt(process.argv[3]) > 0
        ? 0
        : parseInt(process.argv[3])
if (!dir) {
    console.log('No params')
    process.exit()
}

function getDayIndex(offset) {
    let os = offset
    if (!offset) {
        os = 0
    }

    if (!isNaN(startDay)) {
        if (!offset) {
            os = startDay
        } else {
            os = startDay + offset
        }
    }

    const date = new Date()
    if (os) {
        date.setDate(date.getDate() + os)
    }
    return (
        date.getFullYear() +
        '-' +
        ('0' + (date.getMonth() + 1)).slice(-2) +
        '-' +
        ('0' + date.getDate()).slice(-2)
    )
}

function hr(char) {
    console.log(C('blue') + getLetterNTimes(char || '=', cols) + C())
}

function printHeader(text) {
    hr()
    console.log(C('green') + text + C())
    hr()
}

function C(color) {
    if (color !== undefined) {
        color = color.toLowerCase()
    }

    if (color === 'redbg') {
        return '\x1b[41m'
    }
    if (color === 'bluebg') {
        return '\x1b[44m'
    }
    if (color === 'green') {
        return '\x1b[32m'
    }
    if (color === 'red') {
        return '\x1b[31m'
    }
    if (color === 'yellow') {
        return '\x1b[33m'
    }
    if (color === 'blue') {
        return '\x1b[34m'
    }
    if (color === 'magenta') {
        return '\x1b[35m'
    }
    if (color === 'cyan') {
        return '\x1b[36m'
    }
    return '\x1b[0m'
}

function readJSON(name) {
    return JSON.parse(fs.readFileSync(name, 'utf8'))
}

function tail(text, number) {
    const splitedText = text.split('\n')
    return splitedText
        .slice(Math.max(splitedText.length - number, 1))
        .join('\n')
}

function head(text, number) {
    return text.split('\n').slice(0, number).join('\n')
}

function countLinesMatching(text, toMatch) {
    let count = 0
    text.split('\n').forEach((line) => {
        if (line.includes(toMatch.toLowerCase())) {
            count++
        }
    })
    return count
}

function getDayName(day) {
    let d = day
    if (!isNaN(startDay)) {
        d += startDay
    }
    switch (d) {
        case 0:
        case undefined:
            return 'Today'
        case -1:
            return 'Yesterday'
        case -2:
            return 'Before yesterday'
        default:
            const now = new Date()
            now.setDate(now.getDate() + d)
            return now.toDateString()
    }
}

function readFile(name) {
    if (fs.existsSync(name)) {
        return fs.readFileSync(name, 'utf8')
    }
}

function getLetterNTimes(letter, number) {
    let res = ''
    while (res.length < number) {
        res += letter
    }
    return res
}

function pCols(cols, rowTitles, colorNames, firstRowColor) {
    // console.log(cols)
    let maxLength = 0
    cols.reverse().forEach((col, i) => {
        if (i >= colsToPrint) {
            return
        }
        if (col.length > maxLength) {
            maxLength = col.length
        }
    })

    cols.reverse()

    for (let i = 0; i < maxLength; i++) {
        const row = []

        cols.forEach((val, colIndex) => {
            if (colIndex >= colsToPrint) {
                return
            }
            if (!val[i]) {
                row.push(
                    getLetterNTimes(' ', maxStatLength + statNameSpacing + 2)
                )
                return
            }

            const keyName = val[i].name || val[i]

            let slicedName = keyName.slice(0, maxStatLength)
            const toColor = colorNames
                ? Object.keys(coloredWords).reduce((acc, key) => {
                      const colorArray = coloredWords[key]

                      const includes = colorArray.some((colorableIdName) => {
                          return keyName
                              .toLowerCase()
                              .includes(colorableIdName.toLowerCase())
                      })

                      if (includes) {
                          return key
                      }

                      return acc
                  }, '')
                : false

            const sep = (i + 1) % 5 === 0 ? '.' : ' '

            while (slicedName.length < maxStatLength) {
                slicedName = slicedName + sep
            }

            let ammount = val[i].val ? val[i].val.toLocaleString() : ''
            while (ammount.length < 5) {
                ammount = ammount + ' '
            }

            if (toColor) {
                row.push(C(toColor) + slicedName + ' ' + ammount + C())
            } else {
                row.push(slicedName + ' ' + ammount)
            }
        })

        // ROW TITLE ---------------------------------------------------
        let currRowTitle =
            rowTitles && rowTitles[i]
                ? rowTitles[i]
                : getLetterNTimes(' ', beforeRowSpace)

        while (currRowTitle.length < beforeRowSpace) {
            currRowTitle = currRowTitle + ' '
        }
        currRowTitle = C('blue') + currRowTitle + C()
        // COLORING ----------------------------------------------------
        let res = ''
        if (firstRowColor && i === 0) {
            res =
                currRowTitle +
                C('green') +
                row.join(getLetterNTimes(' ', statNameSpacing)) +
                C()
        } else {
            res = currRowTitle + row.join(getLetterNTimes(' ', statNameSpacing))
        }
        // SHOW DIFF ---------------------------------------------------
        console.log(res)
    }
}

function preProcessUIdTestSolving(obj, minLength) {
    if (!obj) {
        return '0'
    }
    if (minLength) {
        return Object.keys(obj)
            .filter((key) => {
                return obj[key] > minLength
            })
            .length.toString()
    } else {
        return Object.keys(obj).length.toString()
    }
}

// ------------------------------------------------------------------------------
printHeader('Daily stats')
try {
    const dailyStats = readJSON(`${dir}stats/vstats`)
    function preProcessDailyStats(obj) {
        const formatted = Object.keys(obj).reduce((acc, key) => {
            const includes = filterFromDailyStats.some((keyword) => {
                return key.toLowerCase().includes(keyword.toLowerCase())
            })
            if (!includes) {
                acc.push({ name: key.replace(/\.html/g, ''), val: obj[key] })
            }
            return acc
        }, [])

        const merged = formatted.reduce((acc, x) => {
            const index = acc.findIndex((y) => {
                return x.name === y.name
            })

            if (index !== -1) {
                acc = acc.map((z, i) => {
                    if (i === index) {
                        return {
                            ...x,
                            val: z.val + x.val,
                        }
                    }
                    return z
                })
            } else {
                acc.push(x)
            }

            return acc
        }, [])

        return merged.sort((a, b) => {
            if (a.name > b.name) {
                return 1
            } else if (a.name < b.name) {
                return -1
            } else {
                return 0
            }
        })
    }
    function getDailyStat(day) {
        return preProcessDailyStats(dailyStats[getDayIndex(day)])
    }

    pCols(
        [
            ...[...Array(colsToPrint).keys()].map((x) => {
                return getDailyStat(-x)
            }),
        ],
        null,
        true
    )
} catch (e) {
    console.error(e)
}

// ------------------------------------------------------------------------------
printHeader('User id test solving')
try {
    const userIdTestSolving = readJSON(`${dir}stats/idvstats`)
    function getUserIdTestSolving(day) {
        return [
            getDayName(day),
            preProcessUIdTestSolving(userIdTestSolving[getDayIndex(day)]),
        ]
    }

    pCols(
        [
            ...[...Array(colsToPrint).keys()].map((x) => {
                return getUserIdTestSolving(-x)
            }),
        ],
        null,
        false,
        'green'
    )
} catch (e) {
    console.error(e)
}

// ------------------------------------------------------------------------------
printHeader('User id requests')
try {
    const clientIdTestSolving = readJSON(`${dir}stats/uvstats`)
    function getUserIdRequests(day) {
        return [
            getDayName(day),
            preProcessUIdTestSolving(clientIdTestSolving[getDayIndex(day)]),
            preProcessUIdTestSolving(clientIdTestSolving[getDayIndex(day)], 5),
        ]
    }

    pCols(
        [
            ...[...Array(colsToPrint).keys()].map((x) => {
                return getUserIdRequests(-x)
            }),
        ],
        ['', 'All', 'More than 5'],
        false,
        'green'
    )

    // ------------------------------------------------------------------------------
    printHeader('Daily data count')
    const dailyDataCount = readFile(`${dir}stats/dailyDataCount`)
    function getDailyDataCount(count) {
        return [...Array(count).keys()].map((x) => {
            return JSON.parse(head(tail(dailyDataCount, x + 1), 1))
        })
    }

    printLastDataCount(getDailyDataCount(colsToPrint))

    function printLastDataCount(data) {
        const res = [...Array(colsToPrint).keys()].map((x) => {
            return [getDayName(-x)]
        })
        data.forEach((dataCount, i) => {
            res[i].push(dataCount.userCount.toLocaleString())
            res[i].push(dataCount.subjectCount.toLocaleString())
            res[i].push(dataCount.questionCount.toLocaleString())
        })

        pCols(res, ['', 'Users', 'Subjects', 'Questions'], false, 'green')
    }
} catch (e) {
    console.error(e)
}
// ------------------------------------------------------------------------------
printHeader('Daily script install / update check count')
try {
    function getDailyScriptStat(day) {
        const log =
            !day || day === 0
                ? readFile(`${dir}stats/vlogs/log`)
                : readFile(`${dir}stats/vlogs/${getDayIndex(day)}`)

        if (!log) {
            return [getDayName(day), 0, 0]
        }
        return [
            getDayName(day),
            countLinesMatching(log, '?install').toLocaleString(),
            countLinesMatching(log, '?up').toLocaleString(),
        ]
    }

    const installs = [...Array(colsToPrint).keys()].map((x) => {
        return getDailyScriptStat(-x)
    })

    pCols(installs, ['', 'Installs', 'Updates'], false, 'green')
} catch (e) {
    console.error(e)
}