const logger = require('winston');
const fs = require('fs');
const db = require('../models');
const config = require('config');

module.exports = {
  validateApiPublishRequest (body, files) {
    if (!body) {
      throw new Error('no body found in request');
    }
    if (!body.name) {
      throw new Error('no name field found in request');
    }
    if (!body.nsfw) {
      throw new Error('no nsfw field found in request');
    }
    if (!files) {
      throw new Error('no files found in request');
    }
    if (!files.file) {
      throw new Error('no file with key of [file] found in request');
    }
  },
  validatePublishSubmission (file, claimName, nsfw) {
    try {
      module.exports.validateFile(file);
      module.exports.validateClaimName(claimName);
      module.exports.validateNSFW(nsfw);
    } catch (error) {
      throw error;
    }
  },
  validateFile (file) {
    if (!file) {
      logger.debug('publish > file validation > no file found');
      throw new Error('no file provided');
    }
    // check the file name
    if (/'/.test(file.name)) {
      logger.debug('publish > file validation > file name had apostrophe in it');
      throw new Error('apostrophes are not allowed in the file name');
    }
    // check file type and size
    switch (file.type) {
      case 'image/jpeg':
      case 'image/jpg':
      case 'image/png':
        if (file.size > 10000000) {
          logger.debug('publish > file validation > .jpeg/.jpg/.png was too big');
          throw new Error('Sorry, images are limited to 10 megabytes.');
        }
        break;
      case 'image/gif':
        if (file.size > 50000000) {
          logger.debug('publish > file validation > .gif was too big');
          throw new Error('Sorry, .gifs are limited to 50 megabytes.');
        }
        break;
      case 'video/mp4':
        if (file.size > 50000000) {
          logger.debug('publish > file validation > .mp4 was too big');
          throw new Error('Sorry, videos are limited to 50 megabytes.');
        }
        break;
      default:
        logger.debug('publish > file validation > unrecognized file type');
        throw new Error('The ' + file.type + ' content type is not supported.  Only, .jpeg, .png, .gif, and .mp4 files are currently supported.');
    }
    return file;
  },
  validateClaimName (claimName) {
    const invalidCharacters = /[^A-Za-z0-9,-]/.exec(claimName);
    if (invalidCharacters) {
      throw new Error('The claim name you provided is not allowed.  Only the following characters are allowed: A-Z, a-z, 0-9, and "-"');
    }
  },
  validateLicense (license) {
    if ((license.indexOf('Public Domain') === -1) && (license.indexOf('Creative Commons') === -1)) {
      throw new Error('Only posts with a "Public Domain" or "Creative Commons" license are eligible for publishing through spee.ch');
    }
  },
  cleanseNSFW (nsfw) {
    switch (nsfw) {
      case true:
      case 'on':
      case 'true':
      case 1:
      case '1':
        return true;
      case false:
      case 'false':
      case 'off':
      case 0:
      case '0':
        return false;
      default:
        return null;
    }
  },
  cleanseChannelName (channelName) {
    if (channelName) {
      if (channelName.indexOf('@') !== 0) {
        channelName = `@${channelName}`;
      }
    }
    return channelName;
  },
  validateNSFW (nsfw) {
    if (nsfw === true || nsfw === false) {
      return;
    }
    throw new Error('NSFW must be set to either true or false');
  },
  createPublishParams (filePath, name, title, description, license, nsfw, thumbnail, channelName) {
    logger.debug(`Creating Publish Parameters`);
    // provide defaults for title
    if (title === null || title.trim() === '') {
      title = name;
    }
    // provide default for description
    if (description === null || description.trim() === '') {
      description = `${name} published via spee.ch`;
    }
    // provide default for license
    if (license === null || license.trim() === '') {
      license = 'All Rights Reserved';
    }
    // create the publish params
    const publishParams = {
      name,
      file_path: filePath,
      bid      : 0.01,
      metadata : {
        description,
        title,
        author  : 'spee.ch',
        language: 'en',
        license,
        nsfw,
      },
      claim_address: config.get('WalletConfig.LbryClaimAddress'),
    };
    // add thumbnail to channel if video
    if (thumbnail !== null) {
      publishParams['metadata']['thumbnail'] = thumbnail;
    }
    // add channel to params, if applicable
    if (channelName) {
      publishParams['channel_name'] = channelName;
    }
    return publishParams;
  },
  deleteTemporaryFile (filePath) {
    fs.unlink(filePath, err => {
      if (err) {
        logger.error(`error deleting temporary file ${filePath}`);
        throw err;
      }
      logger.debug(`successfully deleted ${filePath}`);
    });
  },
  checkClaimNameAvailability (name) {
    return new Promise((resolve, reject) => {
      // find any records where the name is used
      db.File.findAll({ where: { name } })
      .then(result => {
        if (result.length >= 1) {
          const claimAddress = config.get('WalletConfig.LbryClaimAddress');
          // filter out any results that were not published from spee.ch's wallet address
          const filteredResult = result.filter((claim) => {
            return (claim.address === claimAddress);
          });
          // return based on whether any non-spee.ch claims were left
          if (filteredResult.length >= 1) {
            resolve(false);
          } else {
            resolve(true);
          }
        } else {
          resolve(true);
        }
      })
      .catch(error => {
        reject(error);
      });
    });
  },
  checkChannelAvailability (name) {
    return new Promise((resolve, reject) => {
      // find any records where the name is used
      db.Channel.findAll({ where: { channelName: name } })
        .then(result => {
          if (result.length >= 1) {
            return resolve(false);
          }
          resolve(true);
        })
        .catch(error => {
          reject(error);
        });
    });
  },
};