//** REQUEST TYPES **//
export const REQUEST_TYPE_POST = "POST";
export const REQUEST_TYPE_GET = "GET";
export const REQUEST_TYPE_PUT = "PUT";
export const REQUEST_TYPE_DELETE = "DELETE";
//** POST CONTENT TYPES **//
export const CONTENT_TYPE_JSON = "json";
export const CONTENT_TYPE_FORM = "x-www-form-urlencoded";
//** API URLS **//
export const API_STATUS = "/api/v1/status";
export const API_GET_SETTINGS = "/api/v1/settings/site";
export const API_GET_MEMBER_INFO = "/api/v1/settings/member";
export const API_NEW_PAGE = "/api/v1/page/create";
export const API_EDIT_PAGE = "/api/v1/page/write";
export const API_DELETE_PAGE = "/api/v1/page/delete";
export const API_SETTINGS_SYNC = "/api/v1/settings/sync";
export const API_PUBLISH_PAGES = "/api/v1/settings/publish";
export const API_NAV_SYNC = "/api/v1/settings/nav-sync";
export const API_REINDEX_PAGES = "/api/v1/settings/reindex";
export const API_SEND_MAIL = "/api/v1/mailer";
export const API_LOGIN = "/api/v1/login";
//** API TASKS **//
export const AUTH_STATUS = "getAuthStatus";
export const TASK_SETTINGS_WRITE = "writeSettings";
export const TASK_PUBLISH_SITE = "publishSite";
export const TASK_PAGE_CREATE = "createNewPage";
export const TASK_PAGE_EDIT = "editPage";
export const TASK_PAGE_DELETE = "deletePage";
export const TASK_SEND_MAIL = "sendMail";
export const TASK_REINDEX_PAGE = "reIndexPages";
export const TASK_SYNC_SETTNIGS = "syncSite";
export const TASK_SYNC_NAV = "syncNav";
export const TASK_GET_SETTINGS = "getSiteSettings";
export const TASK_GET_MEMBER_INFO = "getMemberInfo";
//** API STATUS **//
export const API_ACCESS_GOOD = "apiUseAuthorized";
export const API_ACCESS_BAD = "apiUseNotAuthorized";

/**
 * A can of methods used to edit install settings, navigation pages and content pages
 */

class FipamoAdminAPI {
  /**
   * @constructor
   * @param {string} baseURL - url of site; uses local when empty
   */
  constructor(baseURL = null) {
    this.percentComplete = 0; //for later
    this.baseURL = null;
    this.status = false;
    if (baseURL) this.baseURL = baseURL;
    //asks server if a session is active
    this._request(this.baseURL ? this.baseURL + API_STATUS : API_STATUS).then(
      (response) => {
        if (response.type === API_ACCESS_GOOD) {
          this.token = response.token;
        } else {
          //don't set token
          //console.log("NO TOKEN");
        }
      }
    );
  }
  /**
   * Promise method for authenticating and starting a session\
   * **POST**`/api/v1/login`
   * @param {Object[]} data - json object that contains data for set up
   * @param {string} data[].handle - handle for site user
   * @param {string} data[].password - password for site user
   * @example
   * api.login(data).then(response=>{
   *    console.log("RESPONSE", response);
   * })
   * @returns {object} json object that contains type and status of login request
   ```
        {
          "message":"Example Message of Affirmation or what you're missing!",
          "type":"exampleType",
        }
   ```
   */
  login(data) {
    return new Promise((resolve, reject) => {
      this.baseURL ? (data.remote = true) : (data.remote = false);
      this.key ? (data.key = this.key) : (data.key = null);
      this._request(
        this.baseURL ? this.baseURL + API_LOGIN : API_LOGIN,
        AUTH_STATUS,
        REQUEST_TYPE_POST,
        CONTENT_TYPE_JSON,
        data
      )
        .then((result) => {
          resolve(result);
        })
        .catch((err) => {
          reject(err);
        });
    });
  }
  /**
   * Method for saving site and navigation settings\
   * **POST**`/api/v1/settings/:task`
   * @param {string} task - settings being synced `config | navigation`
   * @param {object[]} data - json object that contains settings data for [site] or [nav]
   * @param {string} data[].global.base_url - base url for site [site]
   * @param {string} data[].global.title - site title [site]
   * @param {string} data[].global.descriptions - brief site summary [site]
   * @param {string} data[].global.background - url for site feature image for header [site]
   * @param {boolean} data[].global.private - privacy state for site [disabled] [site]
   * @param {boolean} data[].global.renderOnSave - property for publishing site when page saved [disabled] [site]
   * @param {string} data[].global.theme - current theme for site [site]
   * @param {boolean} data[].global.externalAPI - toggle for external API access [site]
   * @param {string} data[].member.handle - current member handle [site]
   * @param {string} data[].member.email - current member email [site]
   * @param {string} data[].email.active - current email protocol being used [site]
   * @param {string} data[].email.smtp.domain - url of smtp service being [site]
   * @param {string} data[].email.smtp.email - email account of smtp service [site]
   * @param {string} data[].email.smtp.password - password for email of smtp service [site]
   * @param {string} data[].email.mailgun.domain - mailgun domain url [site]
   * @param {string} data[].email.mailgun.key - mailgun key [site]
   *
   * @param {string} data[].item.title - page title [nav]
   * @param {string} data[].item.slug - url safe title [nav]
   * @param {string} data[].item.uuid - unique identifier [nav]
   * @param {string} data[].item.path - directory path to associated markdown file [nav]
   * @example
   * api.sync(TASK, data).then(response=>{
   *    console.log("RESPONSE", response);
   * })
   * @returns {object} json object that contains type and status of sync request
   ```
   *
     {
       "message":"Example Message of Affirmation!",
       "type":"exampleType",
     }
   ```
   */
  sync(task, data) {
    return new Promise((resolve, reject) => {
      let url = "";
      switch (task) {
        case "syncSite":
          url = API_SETTINGS_SYNC;
          break;
        case "syncNav":
          url = API_NAV_SYNC;
          break;
      }
      this._request(
        this.baseURL ? this.baseURL + url : url,
        TASK_SETTINGS_WRITE,
        REQUEST_TYPE_POST,
        CONTENT_TYPE_JSON,
        data
      )
        .then((result) => {
          resolve(result);
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  /**
   * Method for retrieving user authorizing user login
   * @param {object[]} data - json object that contains task
   * @param {string} data[].task - publishing task
   * @example
   * api.publish(TASK).then(response=>{
   *    console.log("RESPONSE", response);
   * })
   * @returns {object} json object that contains type and status of publis request
   * ```
      {
        "message":"Example Message of Affirmation!",
        "type":"exampleType",
      }
   * ```
   */
  publish(data) {
    return new Promise((resolve, reject) => {
      this._request(
        //API_PUBLISH_PAGES,
        this.baseURL ? this.baseURL + API_PUBLISH_PAGES : API_PUBLISH_PAGES,
        TASK_PUBLISH_SITE,
        REQUEST_TYPE_POST,
        CONTENT_TYPE_JSON,
        data
      )
        .then((result) => {
          resolve(result);
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  /**
   * Method for handling page creating and editing\
   * **POST**`/api/v1/page/:task`
   * @param {string} task - current page action
   * @param {object[]} form - form object that contains info for current page being edited/created
   * @param {string} form[].id - sequence id for page, leave empty for new page
   * @param {string} form[].uuid - unique identifier for page, leave empty for new page
   * @param {string} form[].layout - current page layout
   * @param {string} form[].current_title - saved url save title for persistence when changing title, leave empty for new page
   * @param {string} form[].content - markdown body of page
   * @param {string} form[].title - current title of page
   * @param {string} form[].created - date page was created, leave empty for new page
   * @param {string} form[].slug - url safe string of page title
   * @param {string} form[].tags - comma separated list of tags
   * @param {boolean} form[].menu - property that indicates page is included in site menu
   * @param {boolean} form[].featured - property that indicates page is featured
   * @param {boolean} form[].published - property that indicates page is public
   * @param {string} form[].form_token - hidden property to authenticate form submission
   * @param {input} form[].feature_image - main image for page
   * @example
   * api.pageActions(TASK, data).then(response=>{
   *    console.log("RESPONSE", response);
   * })
   * @returns {object} json object that contains type and status of page edit request
   ```
      {
        "message":"Example Message of Affirmation!",
        "type":"exampleType",
      }
   ```
   */
  pageActions(task, data) {
    let url, event, content;
    switch (task) {
      case TASK_PAGE_CREATE:
        url = API_NEW_PAGE;
        event = TASK_PAGE_CREATE;
        content = CONTENT_TYPE_FORM;
        break;
      case TASK_PAGE_EDIT:
        url = API_EDIT_PAGE;
        event = TASK_PAGE_EDIT;
        content = CONTENT_TYPE_FORM;
        break;

      case TASK_PAGE_DELETE:
        url = API_DELETE_PAGE;
        event = TASK_PAGE_DELETE;
        content = CONTENT_TYPE_JSON;
        break;

      default:
        break;
    }

    if (this.baseURL) {
      //data.key = this.key;
      data.remote = true;
    } else {
      data.remote = false;
    }

    return new Promise((resolve, reject) => {
      this._request(
        this.baseURL ? this.baseURL + url : url,
        event,
        REQUEST_TYPE_POST,
        content,
        data
      )
        .then((result) => {
          resolve(result);
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  /**
   * Method for sending mail (if completed in settings)\
   * **POST**`/api/v1/mailer`
   * @param {object[]} message - json object that contains items to be included in main site navigation
   * @param {string} message[].content - message to send
   * @example
   * api.sendMail(message).then(response=>{
   *    console.log("RESPONSE", response);
   * })
   * @returns {object} json object that contains type and status of page edit request
   ```
     {
       "message":"Example Message of Affirmation!",
       "type":"exampleType"
     }
   ```
   */
  sendMail(message) {
    return new Promise((resolve, reject) => {
      this._request(
        this.baseURL ? this.baseURL + API_SEND_MAIL : API_SEND_MAIL,
        TASK_SEND_MAIL,
        REQUEST_TYPE_POST,
        CONTENT_TYPE_JSON,
        message
      )
        .then((result) => {
          resolve(result);
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  /**
   * *Promise method for retrieving site and member info*\
   * **GET** `/api/v1/settings/:type`
   * @param {string} type - type of info requested ['site'|'member'];
   * @example
   * api.getInfo("type").then(data=>{
        console.log("Info Object", data);
   * })
   * @returns {object} json object that contains data for requested information
   *
   * *info object example*
   * ```
     {
       "message":"message of affirmation!",
       "task":"type of info request",
       "data":json-data-object,
     }
   * ```
   */

  getInfo(type) {
    let url, task;
    if (type == "site") {
      url = API_GET_SETTINGS;
      task = TASK_GET_SETTINGS;
    } else {
      url = API_GET_MEMBER_INFO;
      task = TASK_GET_MEMBER_INFO;
    }
    return new Promise((resolve, reject) => {
      this._request(this.baseURL ? this.baseURL + url : url, task)
        .then((result) => {
          resolve(result);
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  //--------------------------
  // private
  //--------------------------
  _request(
    requestURL,
    eventType,
    requestType = REQUEST_TYPE_GET,
    contentType = CONTENT_TYPE_JSON,
    requestData = null
  ) {
    var self = this;
    return new Promise(function (resolve, reject) {
      var request = new XMLHttpRequest();
      request.upload.onprogress = self.handleLoadProgress;
      request.open(requestType, requestURL, true);
      request.onload = () => {
        if (request.status == 200) {
          let response = JSON.parse(request["response"]);
          resolve(response);
        } else {
          let error = JSON.parse(request["response"]);
          reject(error);
        }
      };
      if (requestType == REQUEST_TYPE_PUT || requestType == REQUEST_TYPE_POST) {
        if (
          eventType === TASK_SETTINGS_WRITE ||
          eventType === TASK_PAGE_EDIT ||
          eventType === TASK_PAGE_CREATE ||
          eventType === TASK_PAGE_DELETE ||
          eventType === TASK_PUBLISH_SITE ||
          eventType === TASK_REINDEX_PAGE
        )
          request.setRequestHeader("fipamo-access-token", self.token);

        switch (contentType) {
          case CONTENT_TYPE_JSON:
            request.setRequestHeader(
              "Content-type",
              "application/" + contentType
            );
            request.send(JSON.stringify(requestData));
            break;
          case CONTENT_TYPE_FORM:
            request.send(requestData);
            break;
        }
      } else {
        if (
          eventType === TASK_GET_SETTINGS ||
          eventType === TASK_GET_MEMBER_INFO
        ) {
          request.setRequestHeader("fipamo-access-token", self.token);
        }
        request.send();
      }
    });
  }

  //--------------------------
  // event handlers
  //--------------------------
  handleLoadProgress(e) {
    this.percentComplete = Math.ceil((e.loaded / e.total) * 100);
    //pass element to display request progress
  }
}

export { FipamoAdminAPI as default };
