import pageIcon from 'page-icon';
import path from 'path';
import fs from 'fs';
import tmp from 'tmp';
import gitCloud from 'gitcloud';
import helpers from './../helpers/helpers';

const { downloadFile, allowedIconFormats } = helpers;
tmp.setGracefulCleanup();

const GITCLOUD_SPACE_DELIMITER = '-';

function getMaxMatchScore(iconWithScores) {
  return iconWithScores.reduce((maxScore, currentIcon) => {
    const currentScore = currentIcon.score;
    if (currentScore > maxScore) {
      return currentScore;
    }
    return maxScore;
  }, 0);
}

/**
 * also maps ext to icon object
 */
function getMatchingIcons(iconsWithScores, maxScore) {
  return iconsWithScores
    .filter(item => item.score === maxScore)
    .map(item => Object.assign({}, item, { ext: path.extname(item.url) }));
}

function mapIconWithMatchScore(fileIndex, targetUrl) {
  const normalisedTargetUrl = targetUrl.toLowerCase();
  return fileIndex
    .map((item) => {
      const itemWords = item.name.split(GITCLOUD_SPACE_DELIMITER);
      const score = itemWords.reduce((currentScore, word) => {
        if (normalisedTargetUrl.includes(word)) {
          return currentScore + 1;
        }
        return currentScore;
      }, 0);

      return Object.assign({}, item, { score });
    });
}

function inferIconFromStore(targetUrl, platform) {
  const allowedFormats = new Set(allowedIconFormats(platform));

  return gitCloud('https://jiahaog.github.io/nativefier-icons/')
    .then((fileIndex) => {
      const iconWithScores = mapIconWithMatchScore(fileIndex, targetUrl);
      const maxScore = getMaxMatchScore(iconWithScores);

      if (maxScore === 0) {
        return null;
      }

      const iconsMatchingScore = getMatchingIcons(iconWithScores, maxScore);
      const iconsMatchingExt = iconsMatchingScore.filter(icon => allowedFormats.has(icon.ext));
      const matchingIcon = iconsMatchingExt[0];
      const iconUrl = matchingIcon && matchingIcon.url;

      if (!iconUrl) {
        return null;
      }
      return downloadFile(iconUrl);
    });
}

function writeFilePromise(outPath, data) {
  return new Promise((resolve, reject) => {
    fs.writeFile(outPath, data, (error) => {
      if (error) {
        reject(error);
        return;
      }
      resolve(outPath);
    });
  });
}

function inferFromPage(targetUrl, platform, outDir) {
  let preferredExt = '.png';
  if (platform === 'win32') {
    preferredExt = '.ico';
  }

  // todo might want to pass list of preferences instead
  return pageIcon(targetUrl, { ext: preferredExt })
    .then((icon) => {
      if (!icon) {
        return null;
      }

      const outfilePath = path.join(outDir, `/icon${icon.ext}`);
      return writeFilePromise(outfilePath, icon.data);
    });
}

/**
 *
 * @param {string} targetUrl
 * @param {string} platform
 * @param {string} outDir
 */
function inferIconFromUrlToPath(targetUrl, platform, outDir) {
  return inferIconFromStore(targetUrl, platform)
    .then((icon) => {
      if (!icon) {
        return inferFromPage(targetUrl, platform, outDir);
      }

      const outfilePath = path.join(outDir, `/icon${icon.ext}`);
      return writeFilePromise(outfilePath, icon.data);
    });
}

/**
 * @param {string} targetUrl
 * @param {string} platform
 */
function inferIcon(targetUrl, platform) {
  const tmpObj = tmp.dirSync({ unsafeCleanup: true });
  const tmpPath = tmpObj.name;
  return inferIconFromUrlToPath(targetUrl, platform, tmpPath);
}

export default inferIcon;
