package de.ivu.elect.presentation.internet;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

import javax.annotation.Nullable;
import javax.faces.application.Application;
import javax.faces.component.html.HtmlOutputText;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;

import org.apache.commons.lang3.StringUtils;
import org.apache.deltaspike.core.api.scope.ConversationGroup;
import org.apache.deltaspike.core.api.scope.ViewAccessScoped;
import org.primefaces.component.commandlink.CommandLink;
import org.primefaces.component.dashboard.Dashboard;
import org.primefaces.component.panel.Panel;
import org.primefaces.event.DashboardReorderEvent;
import org.primefaces.model.DashboardColumn;
import org.primefaces.model.DashboardModel;
import org.primefaces.model.DefaultDashboardColumn;
import org.primefaces.model.DefaultDashboardModel;

import de.ivu.elect.business.internet.boundary.InternetSeiteConversationStore;
import de.ivu.elect.business.internet.boundary.InternetWidgetEdit;
import de.ivu.elect.business.internet.boundary.InternetWidgetExtendedDAO;
import de.ivu.elect.business.internet.entity.InternetSeite;
import de.ivu.elect.business.internet.entity.InternetWidget;
import de.ivu.elect.business.internet.entity.InternetWidgetTyp;
import de.ivu.elect.business.security.UseCasePermission;
import de.ivu.elect.jee.faces.PreConditionCheck;
import de.ivu.elect.jee.presentation.dynamicform.FormBuilder;
import de.ivu.elect.jee.presentation.redirect.Redirect;
import de.ivu.elect.presentation.AbstractElectEditView;
import de.ivu.elect.presentation.View;
import de.ivu.elect.presentation.hilfe.OnlineHilfeId;


import static de.ivu.elect.presentation.internet.InternetWidgetSearchView.buildTitel;

@ViewAccessScoped
@Named(InternetWidgetAnordnenView.COMPONENT_NAME)
@View(viewId = InternetWidgetAnordnenView.VIEW_ID, useCase = UseCasePermission.INTERNET_WIDGET_EDIT)
@OnlineHilfeId("752")
public class InternetWidgetAnordnenView extends AbstractElectEditView<InternetSeite> {

  public static final String COMPONENT_NAME = "internetWidgetAnordnenView";

  public static final String VIEW_ID = "/internet/internet-widget-anordnen.xhtml";

  public static final String PARENT_VIEW_ID = InternetWidgetSearchView.VIEW_ID;

  private static final long serialVersionUID = 1L;

  private static final int COLUMN_COUNT = 8; // Erstmal willkürlich

  @Inject
  @ConversationGroup(InternetSeiteConversationStore.class)
  private InternetSeiteConversationStore conversationStore;

  @Inject
  private transient InternetWidgetExtendedDAO internetWidgetExtendedDAO;

  @Inject
  private transient InternetWidgetEdit internetWidgetEdit;

  private Dashboard dashboard;

  private DashboardModel model;

  @Nullable
  @PreConditionCheck
  public String checkCondition() {
    if (isEntitySet()) {
      return null;
    }

    return cancel();
  }

  @Override
  protected InternetSeite getEntity() {
    return conversationStore.getEntity();
  }

  @Override
  protected void addProperties(FormBuilder formBuilder, InternetSeite entity) {

  }

  @Override
  public String delete() {
    throw new UnsupportedOperationException();
  }

  @Override
  protected boolean isGebietBearbeitenRechtPruefen() {
    return false;
  }

  @Override
  protected boolean isSavePermissionVorhanden() {
    return hasPermission(UseCasePermission.INTERNET_WIDGET_EDIT);
  }

  @Override
  @Redirect
  public String save() {

    if (model != null) {
      HashMap<String, Long> zeilenNachId = new HashMap<>();
      HashMap<String, Long> spaltenNachId = new HashMap<>();

      for (int col = 0; col < model.getColumns().size(); col++) {
        DashboardColumn column = model.getColumn(col);
        for (int row = 0; row < column.getWidgets().size(); row++) {
          String widget = column.getWidget(row);
          zeilenNachId.put(widget, (long) row + 1);
          spaltenNachId.put(widget, (long) col);
        }
      }

      internetWidgetEdit.savePositionen(getEntity(), zeilenNachId, spaltenNachId);
      addInfoMessage("internet.widget.anordnen.saved");
    }
    return goBack(PARENT_VIEW_ID);

  }

  @Override
  public boolean isBtnCancelRendered() {
    return true;
  }

  @Override
  @Redirect
  public String cancel() {
    return goBack(PARENT_VIEW_ID);
  }

  public boolean isEntitySet() {
    return conversationStore.getEntityPK() != null;
  }

  public String getTitelInternetSeite() {
    return buildTitel(getEntity());
  }

  public Dashboard getDashboard() {
    if (dashboard == null) {
      dashboard = buildDashboard();
    }
    return dashboard;
  }

  public void setDashboard(Dashboard dashboard) {
    this.dashboard = dashboard;
  }

  private Dashboard buildDashboard() {
    FacesContext fc = FacesContext.getCurrentInstance();
    Application application = fc.getApplication();

    Dashboard dashboard = (Dashboard) application.createComponent(fc, Dashboard.COMPONENT_TYPE, Dashboard.DEFAULT_RENDERER);
    dashboard.setId("dashboard");

    List<InternetWidget> widgets = internetWidgetExtendedDAO.findByInternetSeiteOhneHeaderOrdered(getEntity());

    Map<InternetWidgetTyp, AtomicLong> anzahlAktiveWidgetsVomTyp = new HashMap<>();

    for (InternetWidget widget : widgets) {
      AtomicLong count = anzahlAktiveWidgetsVomTyp.computeIfAbsent(widget.getWidgetTyp(), x -> new AtomicLong(0L));
      if (widget.getStatus().isAktiv()) {
        count.incrementAndGet();
      }
    }

    // TODO mal in Ruhe überdenken...

    Map<InternetWidget, Long> zeileFuerWidget = bestimmeZeilen(widgets);
    Map<InternetWidget, Long> spaltenFuerWidget = bestimmeSpalten(widgets, COLUMN_COUNT);

    long platzhalterId = 0;

    model = new DefaultDashboardModel();
    for (int col = 0; col < COLUMN_COUNT; col++) {

      DashboardColumn column = new DefaultDashboardColumn();
      model.addColumn(column);

      for (int row = 0; row < widgets.size(); row++) {

        InternetWidget internetWidget = findeWidget(row, col, zeileFuerWidget, spaltenFuerWidget, widgets);

        Panel panel = (Panel) application.createComponent(fc, Panel.COMPONENT_TYPE, Panel.DEFAULT_RENDERER);
        panel.setClosable(false);
        panel.setCollapsed(true);
        panel.setToggleable(false);
        panel.setStyle("");

        CommandLink iconLink = new CommandLink();
        HtmlOutputText iconText = new HtmlOutputText();
        iconLink.getChildren().add(iconText);
        panel.getFacets().put("actions", iconLink);

        String id;
        if (internetWidget == null) {
          id = "platzhalter_" + platzhalterId++;
          panel.setHeader("");
          panel.setStyle("opacity:0.1;");
          iconText.setStyleClass("fa fa-circle-thin");
        } else {
          id = internetWidget.buildInternetId();
          panel.setHeader(messages.lokalisiere(internetWidget.getWidgetTyp()));
          if (!internetWidget.getStatus().isAktiv()) {
            panel.setStyle("opacity:0.6;");
          }
          iconText.setStyleClass(internetWidget.getWidgetTyp().getIcon());

          if (StringUtils.isNotBlank(internetWidget.getSprungmarke()) || anzahlAktiveWidgetsVomTyp.get(internetWidget.getWidgetTyp()).get() > 1L) {
            panel.setHeader(panel.getHeader() + "*");

            String tooltip = "";
            if (StringUtils.isNotBlank(internetWidget.getSprungmarke())) {
              tooltip = internetWidget.getSprungmarke();
            }
            if (StringUtils.isNotBlank(internetWidget.getBeschreibung())) {
              if (StringUtils.isNotBlank(tooltip)){
                tooltip+=" - ";
              }
              tooltip += internetWidget.getBeschreibung();
            }

            if (anzahlAktiveWidgetsVomTyp.get(internetWidget.getWidgetTyp()).get() > 1L) {
              if (StringUtils.isNotBlank(tooltip)){
                tooltip+=" ";
              }
              tooltip += "(" + internetWidget.buildInternetId() + ")";
            }
            iconLink.getPassThroughAttributes().put("data-tooltip", tooltip);
          }
        }
        panel.setId(id);

        // ELECT-7521
        panel.setStyle(panel.getStyle() + "font-size:0.8em;");

        dashboard.getChildren().add(panel);
        column.addWidget(id);
      }

      dashboard.setModel(model);

    }
    return dashboard;

  }

  private InternetWidget findeWidget(int row, int col, Map<InternetWidget, Long> zeileFuerWidget, Map<InternetWidget, Long> spaltenFuerWidget, List<InternetWidget> widgets) {
    return widgets.stream().filter(widget -> row == zeileFuerWidget.get(widget) && col == spaltenFuerWidget.get(widget)).findFirst().orElse(null);
  }

  private Map<InternetWidget, Long> bestimmeSpalten(List<InternetWidget> widgetsSortiertNachZeilenUndSpalten, int maxColumnCount) {
    Map<InternetWidget, Long> result = new HashMap<>();

    Long letzteWidgetZeile = null;
    Long position = null;
    for (InternetWidget widget : widgetsSortiertNachZeilenUndSpalten) {
      if (!widget.getZeile().equals(letzteWidgetZeile)) {
        position = -1L;
        letzteWidgetZeile = widget.getZeile();
      }
      position++;
      if (position >= maxColumnCount) {
        position = maxColumnCount - 1L;
      }
      result.put(widget, position);

    }

    return result;
  }

  private Map<InternetWidget, Long> bestimmeZeilen(List<InternetWidget> widgetsSortiertNachZeilenUndSpalten) {
    Map<InternetWidget, Long> result = new HashMap<>();
    long aktuelleZeile = -1;
    Long letzteWidgetZeile = null;
    for (InternetWidget widget : widgetsSortiertNachZeilenUndSpalten) {
      if (!widget.getZeile().equals(letzteWidgetZeile)) {
        aktuelleZeile++;
        letzteWidgetZeile = widget.getZeile();
      }
      result.put(widget, aktuelleZeile);

    }

    return result;

  }


  public void handleReorder(DashboardReorderEvent event) {
    // nichts zu tun, Methode ist notwendig, damit das model aktualisiert wird
  }

  @Nullable
  @Override
  @Redirect
  public String reset() {
    dashboard = null;
    model = null;
    return VIEW_ID;
  }
}
