//dotenv
require('dotenv').config();

//ffmpeg
var ffmpeg = require('fluent-ffmpeg');

//nextcloud client
const { Client, Server, GetFilesRecursivelyCommand, CommandStatus } = require("nextcloud-node-client");
const server = new Server({
  basicAuth: {
    password: process.env.nextcloud_PASSWD,
    username: process.env.nextcloud_ID,
  },
  url: process.env.nextcloud_URL,
});

//built-in
const path = require("path");
const fs = require('fs').promises;
const util = require('util');
// const { pipeline } = require('stream');
// const pump = util.promisify(pipeline);

//uuid
const {
  v1: uuidv1,
  v4: uuidv4,
} = require('uuid');

//moment
const moment = require("moment-timezone");

//fastify
const fastify = require("fastify")({
  logger: false,
});
fastify.register(require("fastify-static"), {
  root: path.join(__dirname, "public"),
  prefix: "/"
});
fastify.register(require("fastify-formbody"));
fastify.register(require("fastify-multipart"));
fastify.register(require("point-of-view"), {
  engine: {
    handlebars: require("handlebars")
  }
});

//socket.io
var io = require("socket.io")(fastify.server, {
  pingInterval: 1000,
  pingTimeout: 3000
});

//get '/'
fastify.get("/", function (request, reply) {
  reply.view("/src/pages/parade.html", {});
});

//get '/entry', '/entry/'
["/entry", "/entry/"].forEach(function(item) {
  fastify.get(item, function (request, reply) {
    reply.view("/src/pages/entry.html", {});
  });
});
// --> https://stackoverflow.com/a/40899275
// all the regex didn't work for me -- a 'last resort' method

//get '/list', '/list/'
["/list", "/list/"].forEach(function(item) {
  fastify.get(item, async function (request, reply) {

    //get list
    let list = await fs.readdir('/media/storage/public/sound-parade/');
    console.log(list);
    let folders = [];
    for (const item of list) {
      folders.push({
        foldername: item,
        message: (await fs.readFile('/media/storage/public/sound-parade/' + item + '/message.txt')).toString('utf8')
      })
    }

    reply.view("/src/pages/list.html", {
      list: folders,
    });
  });
});

//get '/entries'
fastify.get("/entries", async function (request, reply) {

  //get list
  let list = await fs.readdir('/media/storage/public/sound-parade/');

  reply.send({ list: list });
});

// //get '/folder:{foldername}'
// fastify.get("/folder/:foldername", async function (request, reply) {
//   reply.send({ foldername: foldername });
// });

//post on '/entry'
fastify.post("/entry", async function (request, reply) {

  // stores files to tmp dir and return paths
  const files = await request.saveRequestFiles();
  let audiofile = files.find(f => f.fieldname == 'audiofile');
  let pixelfile = files.find(f => f.fieldname == 'pixels');
  let tmpdir = path.dirname(audiofile.filepath);
  // console.log(audiofile.fields.message.value);

  //convert to mp3 ?
  if (path.extname(audiofile.filename) !== ".mp3") {
    console.log("convert to mp3...");
    function converter() {
     return new Promise((resolve, reject) => {
       //
       let outputFile = tmpdir + "/converted.mp3";
       // --> https://stackoverflow.com/a/36109219 (a quick tip on fluent-ffmpeg)
       ffmpeg()
       .addInput(audiofile.filepath)
       .on("error", function(err) {
         reject(err);
       })
       .on("end", function() {
         resolve(outputFile);
       })
       .outputOptions('-b:a 192000')
       .output(outputFile)
       .run();
     });
    }
    await converter();
    // console.log(await fs.readdir(tmpdir));
  }

  //upload
  const client = new Client(server);

  //create unique folder ==> timestamp + uuid
  const folder = await client.createFolder("Storage/public/sound-parade/" + moment().tz('Asia/Seoul').format('YYYYMMDD-HHmmss - ') + uuidv1());

  const file = await folder.createFile("audio.mp3", await fs.readFile(tmpdir + '/converted.mp3'));
  const text = await folder.createFile("message.txt", Buffer.from(audiofile.fields.message.value));
  const image = await folder.createFile("pixels.png", await fs.readFile(pixelfile.filepath));

  reply.view("/src/pages/entry.html", {}); //???
});

//socket.io
var score = require("./public/score.json");

//
//there will be 16 rooms called: "room0", "room1", ... , "room15"
//if any other room is requested.. well, we will simply reject.
var roommax = 16;

//
io.on("connection", function(socket) {
  console.log("someone connected.");
  socket.on("disconnect", function() { console.log("someone disconnected."); });

  socket.on("room", function(room, fn) {
    // parseInt(room)
    if (room >= 0 && room < roommax) {
      socket.join("room" + room);
      fn(true);
    } else {
      fn(false);
    }
  });
});

//
var pointer = 0; // pointer : 0 ~ (length-1)
var looper;
(looper = function(timeout) {
  setTimeout(function() {

    //pointer = 20;
    // console.log(score[pointer]);

    //
    for (var index = 0; index < roommax; index++) {

      // NOTE: 'pointer' must be 'remembered' since 'pointer' will increase almost immediately! pass as argument => 'pointed'
      // NOTE: 'index' is same => 'indexed'
      setTimeout(function(pointed, indexed) {

        // io.to("room" + indexed).emit("post", score[pointed]);
        io.to("room" + indexed).emit("post", pointed);

      // }, score[pointer].object.showtime * index, pointer, index);
      }, 30000 * index, pointer, index);
    }

    var timegap = 10000 + Math.random()*(40000);
    console.log(timegap);

    pointer++;
    // if (pointer >= score.length) pointer = 0;
    if (pointer >= 10) pointer = 0; // up to # of folders.

    looper(timegap);
  }, timeout);
})(1000);

//listen
fastify.listen(10000, function (err, address) {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
  console.log(`Your app is listening on ${address}`)
  fastify.log.info(`server listening on ${address}`)
});
