const logger = require('winston');

const { details: { host }, publishing: { disabled, disabledMessage } } = require('@config/siteConfig');

const { sendGATimingEvent } = require('../../../../utils/googleAnalytics.js');
const isApprovedChannel = require('../../../../../utils/isApprovedChannel');
const { publishing: { publishOnlyApproved, approvedChannels } } = require('@config/siteConfig');

const { handleErrorResponse } = require('../../../utils/errorHandlers.js');

const checkClaimAvailability = require('../availability/checkClaimAvailability.js');

const publish = require('./publish.js');
const createPublishParams = require('./createPublishParams.js');
const createThumbnailPublishParams = require('./createThumbnailPublishParams.js');
const parsePublishApiRequestBody = require('./parsePublishApiRequestBody.js');
const parsePublishApiRequestFiles = require('./parsePublishApiRequestFiles.js');
const authenticateUser = require('./authentication.js');

const CLAIM_TAKEN = 'CLAIM_TAKEN';
const UNAPPROVED_CHANNEL = 'UNAPPROVED_CHANNEL';

/*

  route to publish a claim through the daemon

*/

const claimPublish = ({ body, files, headers, ip, originalUrl, user, tor }, res) => {
  // logging
  logger.info('Publish request:', {
    ip,
    headers,
    body,
    files,
  });
  // check for disabled publishing
  if (disabled) {
    return res.status(503).json({
      success: false,
      message: disabledMessage,
    });
  }
  // define variables
  let  channelName, channelId, channelPassword, description, fileName, filePath, fileExtension, fileType, gaStartTime, license, name, nsfw, thumbnail, thumbnailFileName, thumbnailFilePath, thumbnailFileType, title;
  // record the start time of the request
  gaStartTime = Date.now();
  // validate the body and files of the request
  try {
    // validateApiPublishRequest(body, files);
    ({name, nsfw, license, title, description, thumbnail} = parsePublishApiRequestBody(body));
    ({fileName, filePath, fileExtension, fileType, thumbnailFileName, thumbnailFilePath, thumbnailFileType} = parsePublishApiRequestFiles(files));
    ({channelName, channelId, channelPassword} = body);
  } catch (error) {
    return res.status(400).json({success: false, message: error.message});
  }
  // check channel authorization
  authenticateUser(channelName, channelId, channelPassword, user)
    .then(({ channelName, channelClaimId }) => {
      if (publishOnlyApproved && !isApprovedChannel({ longId: channelClaimId }, approvedChannels)) {
        const error = {
          name   : UNAPPROVED_CHANNEL,
          message: 'This spee.ch instance only allows publishing to approved channels',
        };
        throw error;
      }
      return Promise.all([
        checkClaimAvailability(name),
        createPublishParams(filePath, name, title, description, license, nsfw, thumbnail, channelName, channelClaimId),
        createThumbnailPublishParams(thumbnailFilePath, name, license, nsfw),
      ]);
    })
    .then(([ claimAvailable, publishParams, thumbnailPublishParams ]) => {
      if (!claimAvailable) {
        const error = {
          name   : CLAIM_TAKEN,
          message: 'That claim name is already taken',
        };
        throw error;
      }
      // publish the thumbnail, if one exists
      if (thumbnailPublishParams) {
        publish(thumbnailPublishParams, thumbnailFileName, thumbnailFileType);
      }
      // publish the asset
      return publish(publishParams, fileName, fileType);
    })
    .then(result => {
      res.status(200).json({
        success: true,
        message: 'publish completed successfully',
        data   : {
          name,
          claimId : result.claim_id,
          url     : `${host}/${result.claim_id}/${name}`, // for backwards compatability with app
          showUrl : `${host}/${result.claim_id}/${name}`,
          serveUrl: `${host}/${result.claim_id}/${name}${fileExtension}`,
          lbryTx  : result,
        },
      });
      // record the publish end time and send to google analytics
      sendGATimingEvent('end-to-end', 'publish', fileType, gaStartTime, Date.now());
    })
    .catch(error => {
      if ([CLAIM_TAKEN, UNAPPROVED_CHANNEL].includes(error.name)) {
        res.status(400).json({
          success: false,
          message: error.message,
        });
      }
      handleErrorResponse(originalUrl, ip, error, res);
    });
};

module.exports = claimPublish;