// site-comments.js
// Copyright (C) 2022 DTP Technologies, LLC
// License: Apache-2.0

'use strict';

import DtpLog from 'dtp/dtp-log.js';

import UIkit from 'uikit';

import * as picmo from 'picmo';

export default class SiteComments {

  constructor (app) {
    this.app = app;
    this.log = new DtpLog({ name: 'Site Comments', slug: 'comments' });
    this.createEmojiPickers();
  }

  createEmojiPickers ( ) {
    const pickerContainers = document.querySelectorAll('li.comment-emoji-picker:not([data-initialized])');
    for (const container of pickerContainers) {
      const picker = { };

      picker.drop = container.querySelector('.comment-emoji-picker-drop');
      picker.ui = picker.drop.querySelector('.comment-emoji-picker-ui');

      const formId = picker.drop.getAttribute('data-form-id');
      picker.form = document.querySelector(`form#${formId}`);
      picker.input = picker.form.querySelector(`textarea[data-form-id=${formId}]`);
      picker.characterCount = picker.form.querySelector('span.comment-character-count');

      picker.picmo = picmo.createPicker({
        emojisPerRow: 7,
        rootElement: picker.ui,
        theme: picmo.darkTheme,
      });

      picker.picmo.addEventListener('emoji:select', this.onEmojiSelected.bind(this, picker));

      picker.emojiPickerDrop = UIkit.drop(picker.drop);
      UIkit.util.on(picker.drop, 'show', ( ) => {
        this.log.info('SiteComments', 'showing emoji picker');
        picker.picmo.reset();
      });

      container.setAttribute('data-initialized', true);
    }
  }

  async onCommentInput (event) {
    const target = event.currentTarget || event.target;

    const formId = target.getAttribute('data-form-id');
    if (!formId) { return; }

    const form = document.getElementById(formId);
    if (!form) { return; }

    const label = form.querySelector('span.comment-character-count');
    if (!label) { return; }

    label.textContent = numeral(event.target.value.charCount()).format('0,0');
  }

  async showReportCommentForm (event) {
    event.preventDefault();
    event.stopPropagation();

    const resourceType = event.currentTarget.getAttribute('data-resource-type');
    const resourceId = event.currentTarget.getAttribute('data-resource-id');
    const commentId = event.currentTarget.getAttribute('data-comment-id');

    this.closeCommentDropdownMenu(commentId);
    
    try {
      const response = await fetch('/content-report/comment/form', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          resourceType, resourceId, commentId
        }),
      });
      if (!response.ok) {
        throw new Error('failed to load report form');
      }
      const html = await response.text();
      this.currentDialog = UIkit.modal.dialog(html);
    } catch (error) {
      this.log.error('reportComment', 'failed to process comment request', { resourceType, resourceId, commentId, error });
      UIkit.modal.alert(`Failed to report comment: ${error.message}`);
    }

    return true;
  }

  async deleteComment (event) {
    event.preventDefault();
    event.stopPropagation();
    const commentId = (event.currentTarget || event.target).getAttribute('data-comment-id');
    try {
      const response = fetch(`/comment/${commentId}`, { method: 'DELETE' });
      if (!response.ok) {
        throw new Error('Server error');
      }
      this.app.processResponse(response);
    } catch (error) {
      UIkit.modal.alert(`Failed to delete comment: ${error.message}`);
    }
  }

  async blockCommentAuthor (event) {
    event.preventDefault();
    event.stopPropagation();
    
    const resourceType = event.currentTarget.getAttribute('data-resource-type');
    const resourceId = event.currentTarget.getAttribute('data-resource-id');
    const commentId = event.currentTarget.getAttribute('data-comment-id');
    const actionUrl = this.getCommentActionUrl(resourceType, resourceId, commentId, 'block-author');
    
    this.closeCommentDropdownMenu(commentId);

    try {
      this.log.info('blockCommentAuthor', 'blocking comment author', { resourceType, resourceId, commentId });
      const response = await fetch(actionUrl, { method: 'POST'});
      await this.app.processResponse(response);

    } catch (error) {
      this.log.error('reportComment', 'failed to process comment request', { resourceType, resourceId, commentId, error });
      UIkit.modal.alert(`Failed to block comment author: ${error.message}`);
    }

    return true;
  }

  closeCommentDropdownMenu (commentId) {
    const dropdown = document.querySelector(`[data-comment-id="${commentId}"][uk-dropdown]`);
    UIkit.dropdown(dropdown).hide(false);
  }

  getCommentActionUrl (resourceType, resourceId, commentId, action) {
    switch (resourceType) {
      case 'Newsletter':
        return `/newsletter/${resourceId}/comment/${commentId}/${action}`;
      case 'Page':
        return `/page/${resourceId}/comment/${commentId}/${action}`;
      case 'Post':
        return `/post/${resourceId}/comment/${commentId}/${action}`;
      default:
        break;
    }
    throw new Error('Invalid resource type for comment operation');
  }

  async submitCommentVote (event) {
    const target = (event.currentTarget || event.target);
    const commentId = target.getAttribute('data-comment-id');
    const vote = target.getAttribute('data-vote');
    try {
      const response = await fetch(`/comment/${commentId}/vote`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ vote }),
      });
      await this.app.processResponse(response);
    } catch (error) {
      UIkit.modal.alert(`Failed to submit vote: ${error.message}`);
    }
  }

  async openReplies (event) {
    event.preventDefault();
    event.stopPropagation();

    const target = event.currentTarget || event.target;
    const commentId = target.getAttribute('data-comment-id');

    const container = document.querySelector(`.dtp-reply-list-container[data-comment-id="${commentId}"]`);
    const replyList = document.querySelector(`ul.dtp-reply-list[data-comment-id="${commentId}"]`);

    const isOpen = !container.hasAttribute('hidden');
    if (isOpen) {
      container.setAttribute('hidden', '');
      while (replyList.firstChild) {
        replyList.removeChild(replyList.firstChild);
      }
      return;
    }

    try {
      const response = await fetch(`/comment/${commentId}/replies`);
      this.app.processResponse(response);
      this.createEmojiPickers();
    } catch (error) {
      UIkit.modal.alert(`Failed to load replies: ${error.message}`);
    }

    return true;
  }

  async openReplyComposer (event) {
    event.preventDefault();
    event.stopPropagation();

    const target = event.currentTarget || event.target;
    const commentId = target.getAttribute('data-comment-id');
    const composer = document.querySelector(`.dtp-reply-composer[data-comment-id="${commentId}"]`);
    composer.toggleAttribute('hidden');

    return true;
  }

  async loadMoreComments (event) {
    event.preventDefault();
    event.stopPropagation();

    const target = event.currentTarget || event.target;

    const buttonId = target.getAttribute('data-button-id');
    const rootUrl = target.getAttribute('data-root-url');
    const nextPage = target.getAttribute('data-next-page');

    try {
      const response = await fetch(`${rootUrl}?p=${nextPage}&buttonId=${buttonId}`);
      await this.app.processResponse(response);
      this.createEmojiPickers();
    } catch (error) {
      UIkit.modal.alert(`Failed to load more comments: ${error.message}`);
    }
  }

  async onEmojiSelected (picker, event) {
    picker.emojiPickerDrop.hide(false);
    await this.insertContentAtCursor(picker, event.emoji);
    picker.characterCount.textContent = numeral(picker.input.value.charCount()).format('0,0');
  }

  async insertContentAtCursor (picker, content) {
    picker.input.focus();

    if (document.selection) {
      let sel = document.selection.createRange();
      sel.text = content;
    } else if (picker.input.selectionStart || (picker.input.selectionStart === 0)) {
      let startPos = picker.input.selectionStart;
      let endPos = picker.input.selectionEnd;

      let oldLength = picker.input.value.length;
      picker.input.value =
      picker.input.value.substring(0, startPos) +
        content +
        picker.input.value.substring(endPos, picker.input.value.length);

      picker.input.selectionStart = startPos + (picker.input.value.length - oldLength);
      picker.input.selectionEnd = picker.input.selectionStart;
    } else {
      picker.input.value += content;
    }
  }
}