"use strict";

const Promise = require("bluebird"),
  fs = require("fs"),
  config = require("config"),
  moment = require("moment"),
  crypto = require("crypto");

let photoDB = null;

const picturesPath = config.get("picturesPath").replace(/\/$/, "") + "/";

const stat = function (_path) {
  if (_path.indexOf(picturesPath.replace(/\/$/, "")) == 0) {
    _path = _path.substring(picturesPath.length);
  }

  let path = picturesPath + _path;

  return new Promise(function (resolve, reject) {
    fs.stat(path, function (error, stats) {
      if (error) {
        return reject(error);
      }
      return resolve(stats);
    });
  });
}

const rawExtension = /\.nef$/i, extensions = [ "jpg", "jpeg", "png", "gif", "nef" ];

function scanDir(parent, path) {
  let re = new RegExp("\.((" + extensions.join(")|(") + "))$", "i"),
    album = {
      path: path.slice(picturesPath.length), /* path already ends in '/' */
      parent: parent,
    }, albums = [ album ], assets = [];
  
  console.log("Scanning for date fixes: " + (path || "/"));
  return new Promise(function(resolve, reject) {
    fs.readdir(path, function(error, files) {
      if (error) {
        console.warn("Could not readdir: " + path);
        return resolve([]);
      }

      /* Remove 'thumbs' and 'raw' directories from being processed */
      files = files.filter(function(file) {
        for (var i = 0; i < files.length; i++) {
          /* If this file has an original NEF/ORF on the system, don't add the JPG to the DB */
          if (rawExtension.exec(files[i]) && file == files[i].replace(rawExtension, ".jpg")) {
            return false;
          }
          
          /* If there is a different CASE (eg. JPG vs jpg) don't add it, and remove the 'lower case' 
            * version from disk. */
          if (file != files[i] && file.toUpperCase() == files[i]) {
            removeNewerFile(path, file, files[i]);
            console.log("Duplicate file in " + path + ": ", file, files[i]);
            return false;
          }
        }

        return file != "raw" && file != "thumbs" && file != ".git" && file != "corrupt";
      });

      return resolve(files);
    });
  }).then(function(files) {
    return Promise.map(files, function(file) {
      let filepath = path + file;  
      return stat(filepath).then(function(stats) {
        if (stats.isDirectory()) {
          return scanDir(album, filepath + "/").spread(function(_albums, _assets) {
            albums = albums.concat(_albums);
            assets = assets.concat(_assets);
          });
        }

        /* Check file extensions */
        if (!re.exec(file)) {
          return;
        }

        return photoDB.sequelize.query("SELECT photos.id,photos.added FROM photos,albums " +
          "WHERE albums.id=photos.albumId AND albums.path=:path AND photos.filename=:filename " +
            "AND photos.added>:mtime", {
          replacements: {
            mtime: stats.mtime,
            filename: file.replace(rawExtension, ".jpg"),
            path: album.path
          },
          type: photoDB.sequelize.QueryTypes.SELECT
        }).then(function(results) {
          if (results.length == 1) {
            assets.push({
              id: results[0].id,
              mtime: stats.mtime
            });
          }
        });
      });
    });
  }).then(function() {
    return [ albums, assets ];
  });
}

require("./server/db/photos").then(function(db) {
  photoDB = db;
  return scanDir(null, picturesPath).spread(function(albums, assets) {
    console.log(assets.length + " assets have incorrect dates.");
    let toProcess = assets.length, lastMessage = moment(), started = moment();
    return photoDB.sequelize.transaction(function (t) {
      return Promise.map(assets, function(asset) {
        return photoDB.sequelize.query(
          "UPDATE photos SET added=:mtime,taken=:mtime,modified=:mtime WHERE id=:id", {
          replacements: asset,
          transaction: t,
        }).then(function(results) {
          toProcess--;
          if (moment().add(-1, 'seconds') > lastMessage) {
            console.log("Items to be processed: "  + toProcess);
            lastMessage = moment();
          }
        });
      }, {
        concurrency: 5
      });
    }).then(function(result) {
      console.log("Update transaction completed: " + started.toNow());
    })
  });
});
