/* ----------------------------------------------------------------------------

 Question Server
 GitLab: <https://gitlab.com/MrFry/mrfrys-node-server>

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program. If not, see <https://www.gnu.org/licenses/>.

 ------------------------------------------------------------------------- */

const hr = '---------------------------------------------------------------------------------'

module.exports = {
  GetDateString: GetDateString,
  Log: Log,
  DebugLog: DebugLog,
  GetColor: GetColor,
  LogReq: LogReq,
  LogStat: LogStat,
  Load: Load,
  logHashed: logHashed,
  hr: hr,
  C: C
}

const DELIM = C('green') + '|' + C()

const utils = require('../utils/utils.js')
const locLogFile = './stats/logs'
const logFile = '/nlogs/nlogs'
const allLogFile = '/nlogs/log'
const statFile = 'stats/stats'
const vStatFile = 'stats/vstats'
const nologFile = './nolog'

const colors = [
  'green',
  'red',
  'yellow',
  'blue',
  'magenta',
  'cyan'
]

const writeInterval = 10
const debugLevel = parseInt(process.env.NS_LOGLEVEL) || 0
Log('Loglevel is: ' + debugLevel)

let data = {}
let vData = {}
let writes = 0

let noLogips = []

function GetDateString () {
  const m = new Date()
  const d = m.getFullYear() + '/' +
    ('0' + (m.getMonth() + 1)).slice(-2) + '/' +
    ('0' + m.getDate()).slice(-2) + ' ' +
    ('0' + m.getHours()).slice(-2) + ':' +
    ('0' + m.getMinutes()).slice(-2) + ':' +
    ('0' + m.getSeconds()).slice(-2)
  return GetRandomColor(m.getHours().toString()) + d + C()
}

function DebugLog (msg, name, lvl) {
  if (lvl <= debugLevel) {
    if (msg === 'hr') {
      msg = hr
    }
    let s = msg
    let header = `${C('red')}#DEBUG${lvl}#${C('yellow')}${name.toUpperCase()}${C('red')}#${C()}${DELIM}${C()}`
    if (typeof msg !== 'object') {
      s = header + msg
    } else {
      Log(header + 'OBJECT:', 'yellow')
      s = msg
    }
    Log(s, 'yellow')
  }
}

function Log (s, c) {
  let log = s
  if (typeof s !== 'object') {
    let dl = DELIM + C(c)
    log = C(c) + GetDateString() + dl + s + C()
  }

  console.log(log)
  utils.AppendToFile(log, logFile)
}

function LogReq (req, toFile, sc) {
  try {
    let ip = req.headers['cf-connecting-ip'] || req.connection.remoteAddress

    let nolog = noLogips.some((x) => {
      return ip.includes(x)
    })
    if (nolog) {
      return
    }

    let logEntry = GetRandomColor(ip) + ip + C()
    let dl = DELIM
    if (req.url.includes('lred')) {
      dl += C('red')
    }

    const hostname = req.hostname.replace('www.', '').split('.')[0]
    logEntry += dl + hostname + dl + req.headers['user-agent'] + dl + req.method + dl

    logEntry += GetRandomColor(req.url.split('?')[0]) + req.url

    if (sc !== undefined) { logEntry += dl + sc }

    logEntry += C()
    if (!toFile) {
      Log(logEntry)
    } else {
      let defLogs = GetDateString() + dl + logEntry

      utils.AppendToFile(defLogs, locLogFile)
      utils.AppendToFile(defLogs, allLogFile)
    }
  } catch (e) {
    console.log(e)
    Log('Error at logging lol', GetColor('redbg'), true)
  }
}

function parseNoLogFile (newData) {
  noLogips = newData.split('\n')
  if (noLogips[noLogips.length - 1] === '') {
    noLogips.pop()
  }
  noLogips = noLogips.filter((x) => {
    return x !== ''
  })
  Log('\tNo Log IP-s changed: ' + noLogips.join(', '))
}

function setNoLogReadInterval () {
  utils.WatchFile(nologFile, (newData) => {
    parseNoLogFile(newData)
  })

  parseNoLogFile(utils.ReadFile(nologFile))
}

function Load () {
  Log('Loading logger...')
  try {
    var prevData = utils.ReadFile(statFile)
    data = JSON.parse(prevData)
  } catch (e) {
    Log('Error at loading logs! (@ first run its normal)', GetColor('redbg'))
    console.log(e)
  }

  try {
    var prevVData = utils.ReadFile(vStatFile)
    vData = JSON.parse(prevVData)
  } catch (e) {
    Log('Error at loading visit logs! (@ first run its normal)', GetColor('redbg'))
    console.log(e)
  }
  setNoLogReadInterval()
}

function LogStat (url, ip) {
  let nolog = noLogips.some((x) => {
    return x.includes(ip)
  })
  if (nolog) {
    return
  }

  url = url.split('?')[0]
  Inc(url)
  AddVisitStat(url)
  Save()
}

function Inc (value) {
  if (value.startsWith('/?')) { value = '/' }
  if (data[value] === undefined) { data[value] = 0 }
  data[value]++
}

function AddVisitStat (name) {
  var m = new Date()
  const now = m.getFullYear() + '/' + ('0' + (m.getMonth() + 1)).slice(-2) + '/' + ('0' + m.getDate()).slice(-2)
  if (vData[now] === undefined) { vData[now] = {} }
  if (vData[now][name] === undefined) { vData[now][name] = 0 }
  vData[now][name]++
}

function Save () {
  writes++
  if (writes === writeInterval) {
    try {
      utils.WriteFile(JSON.stringify(data), statFile)
      // Log("Stats wrote.");
    } catch (e) {
      Log('Error at writing logs!', GetColor('redbg'))
      console.log(e)
    }
    try {
      utils.WriteFile(JSON.stringify(vData), vStatFile)
      // Log("Stats wrote.");
    } catch (e) {
      Log('Error at writing visit logs!', GetColor('redbg'))
      console.log(e)
    }
    writes = 0
  }
}

function logHashed (x) {
  return GetRandomColor(x.toString()) + x + C()
}

function GetRandomColor (ip) {
  if (!ip) {
    return 'red'
  }

  let res = ip.split('').reduce((res, x) => {
    return res + x.charCodeAt(0)
  }, 0)
  return C(colors[res % colors.length])
}

function GetColor (c) {
  return c
}

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

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