//
// Copyright (c) Microsoft and contributors.  All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//

var fs = require('fs');
var path = require('path');
var utils = require('./utils');

var CacheUtils = {};

function getSpacesFile(context) {
  if (!context.subscription) {
    throw new Error('No current subscription when reading spaces file');
  }
  return path.join(utils.azureDir(), 'spaces.' + context.subscription + '.json');
}

function getSitesFile(subscription) {
  if (!subscription) {
    throw new Error('No current subscription when reading sites file');
  }
  return path.join(utils.azureDir(), 'sites.' + subscription + '.json');
}

function existsInArray(arr, valuetobeChecked) {
  var result = false;
  if (Array.isArray(arr) && valuetobeChecked) {
    result = arr.some(function (val) { return utils.ignoreCaseEquals(val, valuetobeChecked); });
  }
  return result;
}

function getCommitIdsFile(context) {
  return path.join(utils.azureDir(), 'commitids.' + context.subscription + '.json');
}

function readSpaces(context, cb) {
  var cacheFile = getSpacesFile(context);
  if (utils.pathExistsSync(cacheFile)) {
    return fs.readFile(cacheFile, function (err, data) {
      if (!err) {
        var cachedSpaces = JSON.parse(data);
        if (cachedSpaces && cachedSpaces.length) {
          // Check if the spaces have the name property with
          // the right casing for the current version of the
          // CLI. If not, it probably is a cache file from a
          // previous version and, in that case, clear it.
          if (!cachedSpaces[0].name) {
            clear();
            return cb && cb(null, []);
          } else {
            return cb && cb(err, cachedSpaces);
          }
        }
      }

      return cb && cb(err, null);
    });
  }

  return cb && cb(null, []);
}

function saveSpaces(context, spaces, cb) {
  var cacheFile = getSpacesFile(context);
  return fs.writeFile(cacheFile, JSON.stringify(spaces, null, 2), function (err) {
    if(cb) {
      cb(err, spaces);
    }
  });
}

function deleteSpace(context, spaceName, cb) {
  var cacheFile = getSpacesFile(context);
  if (utils.pathExistsSync(cacheFile)) {
    return fs.readFile(cacheFile, function (err, data) {
      var spaces = JSON.parse(data);
      if (spaces && spaces.length) {
        for (var i = 0; i < spaces.length; i++) {
          if (utils.ignoreCaseEquals(spaceName, spaces[i].name)) {
            spaces.splice(i, 1);
            return saveSpaces(context, spaces, cb);
          }
        }
      }
      return cb && cb(err, null);
    });
  }

  return cb && cb(null, null);
}

function readSite(subscription, siteName, cb) {
  var cacheFile = getSitesFile(subscription);
  if (utils.pathExistsSync(cacheFile)) {
    return fs.readFile(cacheFile, function (err, data) {
      if (!err) {
        var sites = JSON.parse(data);
        if (sites && sites.length) {
          // Check if the sites have the name property with
          // the right casing for the current version of the
          // CLI. If not, it probably is a cache file from a
          // previous version and, in that case, clear it.
          if (!sites[0].name) {
            clear();
            return cb && cb(null, null);
          } else {
            for (var i = 0; i < sites.length; i++) {
              if (utils.ignoreCaseEquals(siteName, sites[i].name)) {
                return cb && cb(err, sites[i]);
              }
            }
          }
        }
      }

      return cb && cb(err, null);
    });
  }

  return cb && cb(null, null);
}

function saveSite(subscription, siteName, site, cb) {
  if (!site) {
    throw new Error('Invalid site');
  }
  var cacheFile = getSitesFile(subscription);
  if (utils.pathExistsSync(cacheFile)) {
    return fs.readFile(cacheFile, function (err, data) {
      var sites = JSON.parse(data);
      if (sites && sites.length) {
        var sitefound = 0;
        for (var i = 0; i < sites.length; i++) {
          if (utils.ignoreCaseEquals(siteName, sites[i].name)) {
            sites[i] = site;
            sitefound = 1;
            return saveSites(subscription, sites, cb);
          }
        }
        if (!sitefound) {
          sites.push(site);
        }
        return saveSites(subscription, sites, cb);
      }
      return saveSites(subscription, [site], cb);
    });
  }

  return saveSites(subscription, [site], cb);
}

function deleteSite(subscription, siteName, cb) {
  var cacheFile = getSitesFile(subscription);
  if (utils.pathExistsSync(cacheFile)) {
    return fs.readFile(cacheFile, function (err, data) {
      var sites = JSON.parse(data);
      var newSites = [];
      if (sites && sites.length) {
        for (var i = 0; i < sites.length; i++) {
          var result = sites[i].name.match(/\w+/ig);
          if (!existsInArray(result, siteName)) {
            newSites.push(sites[i]);
          }
        }
        return saveSites(subscription, newSites, cb);
      }
      return cb && cb(err, null);
    });
  }

  return cb && cb(null, null);
}

function saveSites(subscription, sites, cb) {
  var cacheFile = getSitesFile(subscription);
  return fs.writeFile(cacheFile, JSON.stringify(sites, null, 2), function (err) {
    if (cb) {
      cb(err, sites);
    }
  });
}

function saveCommitIds(context, deployments, cb) {
  var cacheFile = getCommitIdsFile(context);
  var commitIds = deployments.map(function (deployment) {
    return {
      shortId: deployment.shortId,
      id: deployment.id
    };
  });
  return fs.writeFile(cacheFile, JSON.stringify(commitIds, null, 2), function (err) {
    if (cb) {
      cb(err, deployments);
    }
  });
}

function readCommitId(context, cb) {
  var cacheFile = getCommitIdsFile(context);
  if (utils.pathExistsSync(cacheFile)) {
    return fs.readFile(cacheFile, function (err, data) {
      var commitIds = JSON.parse(data);
      if (commitIds && commitIds.length) {
        for (var i = 0; i < commitIds.length; i++) {
          if (utils.ignoreCaseEquals(context.shortId, commitIds[i].shortId) ||
            utils.ignoreCaseEquals(context.shortId, commitIds[i].id)) {
            return cb && cb(err, commitIds[i].id);
          }
        }
      }
      return cb && cb(err, null);
    });
  }

  return cb && cb(null, null);
}

function clear() {
  var isDeleted = false;
  if (utils.pathExistsSync(utils.azureDir())) {
    var cacheFiles = fs.readdirSync(utils.azureDir());
    for (var i = 0; i < cacheFiles.length; ++i) {
      if (/sites[.].+[.]json/.test(cacheFiles[i]) ||
         /spaces[.].+[.]json/.test(cacheFiles[i]) ||
         /commitids[.].+[.]json/.test(cacheFiles[i])) {
        fs.unlinkSync(path.join(utils.azureDir(), cacheFiles[i]));
        isDeleted = true;
      }
    }
  }
  return isDeleted;
}

CacheUtils.readSpaces = readSpaces;
CacheUtils.saveSpaces = saveSpaces;
CacheUtils.deleteSpace = deleteSpace;
CacheUtils.readSite = readSite;
CacheUtils.saveSite = saveSite;
CacheUtils.deleteSite = deleteSite;
CacheUtils.saveSites = saveSites;
CacheUtils.saveCommitIds = saveCommitIds;
CacheUtils.readCommitId = readCommitId;
CacheUtils.clear = clear;

module.exports = CacheUtils;