'use strict';

/**
 * Dependencies
 */
const toCamelCase = require('../helpers/to-camel-case');
const toSnakeCase = require('../helpers/to-snake-case');
const deepClone = require('../helpers/deep-clone');
const fs = require('fs');
const path = require('path');

/**
 * Attachment class
 */
class Attachment {

  /**
   * Constructor
   */
  constructor(data) {

    //Create from data
    if (data) {
      this.fromData(data);
    }
  }

  /**
   * From data
   */
  fromData(data) {

    //Expecting object
    if (typeof data !== 'object') {
      throw new Error('Expecting object for Mail data');
    }

    //Convert to camel case to make it workable, making a copy to prevent
    //changes to the original objects
    data = deepClone(data);
    data = toCamelCase(data);

    //Extract properties from data
    const {
      content,
      filename,
      type,
      disposition,
      contentId,
      filePath,
    } = data;

    if ((typeof content !== 'undefined') && (typeof filePath !== 'undefined')) {
      throw new Error(
        "The props 'content' and 'filePath' cannot be used together."
      );
    }

    //Set data
    this.setFilename(filename);
    this.setType(type);
    this.setDisposition(disposition);
    this.setContentId(contentId);
    this.setContent(filePath ? this.readFile(filePath) : content);
  }

  /**
   * Read a file and return its content as base64
   */
  readFile(filePath) {
    return fs.readFileSync(path.resolve(filePath));
  }

  /**
   * Set content
   */
  setContent(content) {
    //Duck type check toString on content if it's a Buffer as that's the method that will be called.
    if (typeof content === 'string') {
      this.content = content;
      return;
    } else if (content instanceof Buffer && content.toString !== undefined) {
      this.content = content.toString();

      if (this.disposition === 'attachment') {
        this.content = content.toString('base64');
      }

      return;
    }

    throw new Error('`content` expected to be either Buffer or string');
  }

  /**
   * Set content
   */
  setFileContent(content) {
    if (content instanceof Buffer && content.toString !== undefined) {
      this.content = content.toString('base64');
      return;
    }

    throw new Error('`content` expected to be Buffer');
  }

  /**
   * Set filename
   */
  setFilename(filename) {
    if (typeof filename === 'undefined') {
      return;
    }
    if (filename && typeof filename !== 'string') {
      throw new Error('String expected for `filename`');
    }
    this.filename = filename;
  }

  /**
   * Set type
   */
  setType(type) {
    if (typeof type === 'undefined') {
      return;
    }
    if (typeof type !== 'string') {
      throw new Error('String expected for `type`');
    }
    this.type = type;
  }

  /**
   * Set disposition
   */
  setDisposition(disposition) {
    if (typeof disposition === 'undefined') {
      return;
    }
    if (typeof disposition !== 'string') {
      throw new Error('String expected for `disposition`');
    }
    this.disposition = disposition;
  }

  /**
   * Set content ID
   */
  setContentId(contentId) {
    if (typeof contentId === 'undefined') {
      return;
    }
    if (typeof contentId !== 'string') {
      throw new Error('String expected for `contentId`');
    }
    this.contentId = contentId;
  }

  /**
   * To JSON
   */
  toJSON() {

    //Extract properties from self
    const {content, filename, type, disposition, contentId} = this;

    //Initialize with mandatory properties
    const json = {content, filename};

    //Add whatever else we have
    if (typeof type !== 'undefined') {
      json.type = type;
    }
    if (typeof disposition !== 'undefined') {
      json.disposition = disposition;
    }
    if (typeof contentId !== 'undefined') {
      json.contentId = contentId;
    }

    //Return
    return toSnakeCase(json);
  }
}

//Export class
module.exports = Attachment;
