/*
 * Copyright (C) 2000 - 2024 Silverpeas
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * As a special exception to the terms and conditions of version 3.0 of
 * the GPL, you may redistribute this Program in connection with Free/Libre
 * Open Source Software ("FLOSS") applications as described in Silverpeas's
 * FLOSS exception. You should have received a copy of the text describing
 * the FLOSS exception, and it is also available here:
 * "https://www.silverpeas.org/legal/floss_exception.html"
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
 */
package org.silverpeas.components.infoletter.model;

import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.silverpeas.core.ResourceReference;
import org.silverpeas.core.WAPrimaryKey;
import org.silverpeas.core.admin.user.model.User;
import org.silverpeas.core.contribution.content.ddwe.model.DragAndDropWebEditorStore;
import org.silverpeas.core.contribution.content.renderer.ContributionContentRenderer;
import org.silverpeas.core.contribution.content.wysiwyg.service.WysiwygController;
import org.silverpeas.core.contribution.model.ContributionContent;
import org.silverpeas.core.contribution.model.ContributionIdentifier;
import org.silverpeas.core.contribution.model.WysiwygContent;
import org.silverpeas.core.ddwe.DragAndDropEditorContent;
import org.silverpeas.core.i18n.I18NHelper;
import org.silverpeas.core.persistence.jdbc.bean.SilverpeasBean;
import org.silverpeas.kernel.annotation.NonNull;
import org.silverpeas.kernel.util.StringUtil;
import org.silverpeas.core.util.URLUtil;

import java.util.Objects;
import java.util.Optional;

import static java.util.Optional.ofNullable;
import static org.silverpeas.components.infoletter.model.InfoLetterPublicationPdC.TYPE;
import static org.silverpeas.core.contribution.content.wysiwyg.service.WysiwygController.copyDocumentsBetweenTwoResourcesWithSourceContent;
import static org.silverpeas.kernel.util.StringUtil.EMPTY;
import static org.silverpeas.kernel.util.StringUtil.isNotDefined;

/**
 * @author frageade
 */
@SuppressWarnings("deprecation")
public class InfoLetterPublication extends SilverpeasBean implements Comparable<InfoLetter> {
  private static final long serialVersionUID = 2579802983989822400L;
  public static final int PUBLICATION_EN_REDACTION = 1;
  public static final int PUBLICATION_VALIDEE = 2;

  /**
   * instance identifier
   */
  private String instanceId;

  /**
   * publication title
   */
  private String title;

  /**
   * publication description
   */
  private String description;

  /**
   * publish date
   */
  private String parutionDate;

  /**
   * publication state
   */
  private int publicationState;

  /**
   * letter identifier
   */
  private int letterId;

  private WysiwygContent content;

  /**
   * Default constructor
   */
  public InfoLetterPublication() {
    super();
    title = "";
    description = "";
    parutionDate = "";
    publicationState = PUBLICATION_EN_REDACTION;
    letterId = 0;
  }

  public InfoLetterPublication(WAPrimaryKey pk, String instanceId, String title, String description,
      String parutionDate, int publicationState, int letterId) {
    super();
    setPK(pk);
    this.instanceId = instanceId;
    this.title = title;
    this.description = description;
    this.parutionDate = parutionDate;
    this.publicationState = publicationState;
    this.letterId = letterId;
  }

  public ContributionIdentifier getIdentifier() {
    return ContributionIdentifier.from(getInstanceId(), getPK().getId(), TYPE);
  }

  public String getInstanceId() {
    return instanceId;
  }

  public void setInstanceId(String instanceId) {
    this.instanceId = instanceId;
  }

  public String getTitle() {
    return title;
  }

  public void setTitle(String title) {
    this.title = title;
  }

  public String getDescription() {
    return description;
  }

  public void setDescription(String description) {
    this.description = description;
  }

  public String getParutionDate() {
    return parutionDate;
  }

  public void setParutionDate(String parutionDate) {
    this.parutionDate = parutionDate;
  }

  public int getPublicationState() {
    return publicationState;
  }

  public void setPublicationState(int publicationState) {
    this.publicationState = publicationState;
  }

  public int getLetterId() {
    return letterId;
  }

  @SuppressWarnings("unused")
  public void setLetterId(int letterId) {
    this.letterId = letterId;
  }

  public void setLetterId(String letterId) {
    this.letterId = Integer.parseInt(letterId);
  }

  public String getPermalink() {
    return URLUtil.getSimpleURL(URLUtil.URL_NEWSLETTER, getPK().getId());
  }

  @Override
  public int compareTo(@NonNull InfoLetter obj) {
    Objects.requireNonNull(obj);
    return (String.valueOf(getPK().getId())).compareTo(String.valueOf(obj.getPK().getId()));
  }

  @Override
  public boolean equals(final Object o) {
    if (this == o) {
      return true;
    }
    if (!(o instanceof InfoLetter)) {
      return false;
    }

    final InfoLetter that = (InfoLetter) o;
    return compareTo(that) == 0;
  }

  @Override
  public int hashCode() {
    return new HashCodeBuilder()
        .append(getPK().getId())
        .append(getPK().getInstanceId())
        .toHashCode();
  }

  @Override
  @NonNull
  protected String getTableName() {
    return "SC_IL_Publication";
  }

  public boolean isValid() {
    return (publicationState == PUBLICATION_VALIDEE);
  }

  /**
   * Initializing the content from the given template.
   * <p>
   *   The initialization is using WYSIWYG services and {@link InfoLetterPublication} storing in
   *   order to handle properly document copying.
   * </p>
   * @param infoLetter the template.
   */
  public void initFrom(final InfoLetter infoLetter) {
    final String templateContent = Optional.of(new DragAndDropWebEditorStore(infoLetter.getTemplateIdentifier()))
        .map(DragAndDropWebEditorStore::getFile)
        .filter(DragAndDropWebEditorStore.File::exists)
        .map(DragAndDropWebEditorStore.File::getContainer)
        .flatMap(DragAndDropWebEditorStore.Container::getContent)
        .map(DragAndDropWebEditorStore.Content::getValue)
        // If no store exists for template, then taking the template from WYSIWYG context if any
        .orElseGet(() -> infoLetter.getTemplateWysiwygContent()
            .map(ContributionContent::getRenderer)
            .map(ContributionContentRenderer::renderEdition)
            .filter(StringUtil::isDefined)
            .orElse(EMPTY));
    // Attaching all documents linked to template to the new parution
    final ResourceReference templateRef = infoLetter.getTemplateIdentifier().toReference();
    final ResourceReference parutionRef = getIdentifier().toReference();
    final String newContent = copyDocumentsBetweenTwoResourcesWithSourceContent(templateRef,
        parutionRef, templateContent).getFirst();
    // Saving the new content into Drag And Drop context.
    final DragAndDropWebEditorStore store = new DragAndDropWebEditorStore(getIdentifier());
    store.getFile().getContainer().getOrCreateTmpContent().setValue(newContent);
    store.getFile().getContainer().getOrCreateContent().setValue(newContent);
    store.save();
    // Saving WYSIWYG content (which represents the final content).
    saveContent(new DragAndDropEditorContent(newContent).getInlinedHtml());
  }

  public Optional<WysiwygContent> getWysiwygContent() {
    if (this.content == null) {
      this.content = WysiwygController.get(getInstanceId(), getPK().getId(),
          I18NHelper.DEFAULT_LANGUAGE);
    }
    return ofNullable(this.content);
  }

  /**
   * Saves given content.
   * <p>
   *   The given content MAY be directly a WYSIWYG content, in a such case the content has been
   *   edited by a WYSIWYG editor.
   * </p>
   * <p>
   *   The given content is not defined, in a such case the content has been MAYBE edited by a
   *   Drag And Drop Web Editor. Then the temporary content is saved into final one and the
   *   Inlined HTML is saved into WYSIWYG repository.
   * </p>
   * @param manualContent a manual content. The content is specified when it comes directly from
   * a WYSIWYG editing.
   */
  public void saveContent(final String manualContent) {
    this.content = null;
    final ContributionIdentifier identifier = getIdentifier();
    String wysiwygContent = manualContent;
    if (isNotDefined(manualContent)) {
      // For now looking into Drag & Drop Edition Content
      final DragAndDropWebEditorStore store = new DragAndDropWebEditorStore(identifier);
      wysiwygContent = store.getFile()
          .getContainer()
          .getTmpContent()
          .map(DragAndDropWebEditorStore.Content::getValue)
          .map(c -> {
            store.getFile().getContainer().getOrCreateContent().setValue(c);
            store.save();
            final DragAndDropEditorContent editorContent = new DragAndDropEditorContent(c);
            return editorContent.getInlinedHtml();
          })
          .orElse(manualContent);
    }
    // Update the Wysiwyg if exists, create one otherwise
    WysiwygController.updateFileAndAttachment(wysiwygContent, identifier.getComponentInstanceId(),
        identifier.getLocalId(), User.getCurrentUser().getId(), I18NHelper.DEFAULT_LANGUAGE);
  }

  /**
   * Deletes contents linked to the publication (WYSIWYG and DDWE ones).
   */
  public void deleteContent() {
    final ContributionIdentifier identifier = getIdentifier();
    WysiwygController.deleteWysiwygAttachments(identifier.getComponentInstanceId(),
        identifier.getLocalId());
    new DragAndDropWebEditorStore(identifier).delete();
  }
}
