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

//ffmpeg
var ffmpeg = require('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.hbs", {});
});

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

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

    let params = {};

    //
    const client = new Client(server);

    //files
    const sourceFolder = await client.getFolder("/Storage/public/sound-parade/");
    // const folderFiles = await sourceFolder.getFiles();
    // for (const file of folderFiles) {
    //   console.log(file.name);
    // }

    const subFolders = await sourceFolder.getSubFolders();
    for (const subFolder of subFolders) {
        console.log("folder", subFolder.name);
    }

    // // only pdfs and jpg should be listed
    // // const fileFilterFunction = (file) => {
    // //     // if (file.mime === "application/pdf" || file.mime === "image/jpeg") {
    // //     //     return file;
    // //     // }
    // //     return file;
    // // }
    //
    // const options = {
    //     sourceFolder,
    //     // filterFile: fileFilterFunction,
    // };
    //
    // const command = new GetFilesRecursivelyCommand(client, options);
    // // get files asynchronously (will not throw exceptions!)
    // command.execute();
    //
    // // check the processing status as long as the command is running
    // while (command.isFinished() !== true) {
    //     // wait one second
    //     await (async () => { return new Promise(resolve => setTimeout(resolve, 1000)) })();
    //     console.log(command.getPercentCompleted() + "%");
    // }
    //
    // // use the result to do the needful
    // const uploadResult = command.getResultMetaData();
    //
    // if (command.getStatus() === CommandStatus.success) {
    //     console.log(uploadResult.messages);
    //     for (const file of command.getFiles()) {
    //         console.log(file.name);
    //     }
    // } else {
    //     console.log(uploadResult.errors);
    // }

    reply.view("/src/pages/list.hbs", params);
  });
});

//'post'
fastify.post("/", 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');
  // console.log(audiofile.fields.message.value);

  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());

  //convert to mp3
  let dir = path.dirname(audiofile.filepath);
  try {
		var process = new ffmpeg(audiofile.filepath);
		process.then(function (video) {
			// Callback mode
			video.fnExtractSoundToMP3(dir + '/converted.mp3', function (error, file) {
				if (!error)
					console.log('Audio file: ' + file);
			});
		}, function (err) {
			console.log('Error: ' + err);
		});
	} catch (e) {
		console.log(e.code);
		console.log(e.msg);
	}
  // await new ffmpeg(audiofile.filepath)
  //
  // await util.promisify((await new ffmpeg(name)).fnExtractSoundToMP3("converted.mp3"));

  const file = await folder.createFile(audiofile.filename, await fs.readFile(audiofile.filepath));
  // const text = await folder.createFile("message.txt", Buffer.from(audiofile.fields.message.value));
  // const image = await folder.createFile(pixelfile.filename, await fs.readFile(pixelfile.filepath));

  // //mp3 conversion
  // console.log(await fs.readdir(dir));
  //
  //
  console.log(await fs.readdir(dir));

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

//
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]);

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

    var timegap = score[pointer].timegap.base + Math.random()*score[pointer].timegap.random;
    // console.log(timegap);

    pointer++;
    if (pointer >= score.length) pointer = 0;

    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}`)
});
