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

 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 express = require('express')
const bodyParser = require('body-parser')
const busboy = require('connect-busboy')
const fs = require('fs')
const app = express()
let url = ''

const logger = require('../../utils/logger.js')
// const utils = require('../utils/utils.js')
// const actions = require('../utils/actions.js')

const listedFiles = './public/files'

function GetApp () {
  app.set('view engine', 'ejs')
  app.set('views', [
    './modules/stuff/views',
    './sharedViews'
  ])
  app.use(express.static('public'))
  app.use(busboy({
    limits: {
      fileSize: 10000 * 1024 * 1024
    }
  }))
  app.use(bodyParser.json())
  app.use(bodyParser.urlencoded({
    limit: '5mb',
    extended: true
  }))
  app.use(bodyParser.json({
    limit: '5mb'
  }))

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

  // app, '/*.mp4', 'video/mp4', 'stuff/video'
  function appGetFileType (app, wildcard, contentType, pageToRender) {
    app.get(wildcard, function (req, res) {
      let p = decodeURI(req.url)
      let fp = p
      if (p.includes('?')) {
        fp = p.split('?')
        fp.pop()
        fp = fp.join('/')
      }
      const fpath = './public/files' + fp
      if (!fs.existsSync(fpath)) {
        res.render('nofile', {
          missingFile: fpath,
          url
        })
        return
      }
      if (req.query.stream || !pageToRender) {
        const stat = fs.statSync(fpath)
        const fileSize = stat.size
        const range = req.headers.range
        if (range) {
          const parts = range.replace(/bytes=/, '').split('-')
          const start = parseInt(parts[0], 10)
          const end = parts[1]
            ? parseInt(parts[1], 10)
            : fileSize - 1
          const chunksize = (end - start) + 1
          const file = fs.createReadStream(fpath, { start, end })
          const head = {
            'Content-Range': `bytes ${start}-${end}/${fileSize}`,
            'Accept-Ranges': 'bytes',
            'Content-Length': chunksize,
            'Content-Type': contentType
          }
          res.writeHead(206, head)
          file.pipe(res)
        } else {
          const head = {
            'Content-Length': fileSize,
            'Content-Type': contentType
          }
          res.writeHead(200, head)
          fs.createReadStream(fpath).pipe(res)
        }
      } else {
        logger.LogReq(req)
        let fname = fpath.split('/')
        fname = fname.pop()
        res.render(pageToRender, {
          path: fp,
          fname,
          url,
          contentType,
          albumArt: GetAlbumArt(p)
        })
      }
    })
  }

  const fileTypes = [
    ['/*.mp4', 'video/mp4', 'video'],
    ['/*.mkv', 'audio/x-matroska', 'video'],
    ['/*.mp3', 'audio/mpeg', 'audio'],
    ['/*.pdf', 'application/pdf'],
    ['/*.zip', 'application/zip']
  ]

  function GetAlbumArt (path) {
    let tmp = path.split('.')
    tmp.pop()
    tmp = tmp.join('.').split('/')
    let last = tmp.pop()

    return tmp.join('/') + '/.' + last + '.png'
  }

  fileTypes.forEach((t) => {
    appGetFileType(app, t[0], t[1], t[2])
  })

  app.get('/*', function (req, res) {
    let parsedUrl = decodeURI(req.url)
    let curr = listedFiles + '/' + parsedUrl.substring('/'.length, parsedUrl.length).split('?')[0]
    let relPath = curr.substring('./public/files'.length, curr.length)

    if (relPath[relPath.length - 1] !== '/') { relPath += '/' }

    let t = relPath.split('/')
    let prevDir = ''
    for (let i = 0; i < t.length - 2; i++) { prevDir += t[i] + '/' }

    // curr = curr.replace(/\//g, "/");
    // relPath = relPath.replace(/\//g, "/");

    logger.LogReq(req)

    try {
      const stat = fs.lstatSync(curr)
      if (stat.isDirectory() || stat.isSymbolicLink()) {
        if (curr[curr.length - 1] !== '/') { curr += '/' }

        let f = []

        fs.readdirSync(curr).forEach((item) => {
          if (item[0] !== '.') {
            let res = { name: item }
            let stat = fs.statSync(curr + '/' + item)

            let fileSizeInBytes = stat['size']
            res.size = Math.round(fileSizeInBytes / 1000000)

            res.path = relPath
            if (res.path[res.path.length - 1] !== '/') { res.path += '/' }
            res.path += item

            res.mtime = stat['mtime'].toLocaleString()
            res.isDir = stat.isDirectory()

            f.push(res)
          }
        })

        res.render('folders', {
          folders: f,
          dirname: relPath,
          prevDir,
          url
        })
      } else {
        let fileStream = fs.createReadStream(curr)
        fileStream.pipe(res)
      }
    } catch (e) {
      res.render('nofile', {
        missingFile: curr,
        url
      })
    }
  })

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

  app.get('*', function (req, res) {
    res.status(404).render('404')
  })

  app.post('*', function (req, res) {
    res.status(404).render('404')
  })

  return {
    app: app
  }
}

exports.name = 'Stuff'
exports.getApp = GetApp
exports.setup = (x) => {
  url = x.url
}