/**
 * This file is part of the Meeds project (https://meeds.io/).
 *
 * Copyright (C) 2020 - 2024 Meeds Association contact@meeds.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 * 
 * 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
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package io.meeds.analytics.portlet;

import java.io.IOException;
import java.time.Instant;
import java.time.LocalDate;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import javax.portlet.*;
import javax.ws.rs.core.MediaType;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONObject;

import io.meeds.analytics.model.StatisticFieldMapping;
import io.meeds.analytics.model.filter.*;
import io.meeds.analytics.model.filter.aggregation.AnalyticsAggregation;
import io.meeds.analytics.model.filter.aggregation.AnalyticsPercentageLimit;
import io.meeds.analytics.model.filter.search.AnalyticsFieldFilter;
import io.meeds.analytics.utils.AnalyticsUtils;

public class AnalyticsRatePortlet extends AbstractAnalyticsPortlet<AnalyticsPercentageFilter> {

  protected String getViewPagePath() {
    return "/WEB-INF/jsp/analytics-rate.jsp";
  }

  @Override
  protected Class<AnalyticsPercentageFilter> getFilterClass() {
    return AnalyticsPercentageFilter.class;
  }

  @Override
  protected void readSettingsReadOnly(ResourceRequest request, ResourceResponse response) throws PortletException, IOException {
    AnalyticsPercentageFilter filter = getFilter(request);
    JSONObject jsonResponse = new JSONObject();
    addJSONParam(jsonResponse, "title", filter.getTitle());
    addJSONParam(jsonResponse, "chartType", filter.getChartType());
    addJSONParam(jsonResponse, "colors", filter.getColors());
    addJSONParam(jsonResponse, "canEdit", canModifySettings(request));
    response.setContentType(MediaType.APPLICATION_JSON);
    response.getWriter().write(jsonResponse.toString());
  }

  @Override
  protected void readSettings(ResourceRequest request, ResourceResponse response) throws PortletException, IOException {
    AnalyticsPercentageFilter filter = getFilter(request);
    response.setContentType(MediaType.APPLICATION_JSON);
    response.getWriter().write(AnalyticsUtils.toJsonString(filter));
  }

  @Override
  protected void readData(ResourceRequest request, ResourceResponse response) throws PortletException, IOException {
    AnalyticsPercentageFilter filter = getFilter(request);
    addLanguageFilter(request, filter);
    addTimeZoneFilter(request, filter);
    addPeriodFilter(request, filter);
    Object result = getAnalyticsService().computePercentageChartData(filter);
    response.setContentType(MediaType.APPLICATION_JSON);
    response.getWriter().write(AnalyticsUtils.toJsonString(result));
  }

  private void addLanguageFilter(ResourceRequest request, AnalyticsPercentageFilter filter) {
    String lang = request.getParameter("lang");
    filter.setLang(lang);
  }

  private void addPeriodFilter(ResourceRequest request, AnalyticsPercentageFilter filter) {
    String fromDateString = request.getParameter("min");
    String toDateString = request.getParameter("max");
    String periodType = request.getParameter("periodType");

    AnalyticsPeriod period = new AnalyticsPeriod(Long.parseLong(fromDateString), Long.parseLong(toDateString), filter.zoneId());
    if (StringUtils.isNotBlank(periodType)) {
      AnalyticsPeriodType analyticsPeriodType = AnalyticsPeriodType.periodTypeByName(periodType);
      long middleOfPeriod = (period.getFromInMS() + period.getToInMS()) / 2;
      LocalDate middlePeriodDate = Instant.ofEpochMilli(middleOfPeriod).atZone(filter.zoneId()).toLocalDate();
      period = analyticsPeriodType.getCurrentPeriod(middlePeriodDate, filter.zoneId());
      middleOfPeriod = (period.getFromInMS() + period.getToInMS()) / 2;
      filter.setPeriodDateInMS(middleOfPeriod);
      filter.setPeriodType(periodType);
    } else {
      filter.setCustomPeriod(period);
    }
  }

  private AnalyticsPercentageFilter getFilter(ResourceRequest request) {
    AnalyticsPercentageFilter filter = getFilterFromPreferences(request);
    Set<StatisticFieldMapping> mappings = getAnalyticsService().retrieveMapping(false);
    Set<String> fieldNames = mappings.stream()
                                     .map(StatisticFieldMapping::getName)
                                     .collect(Collectors.toSet());

    convertToAltFieldName(filter.getValue(), fieldNames);
    convertToAltFieldName(filter.getThreshold(), fieldNames);

    AnalyticsPercentageLimit percentageLimit = filter.getPercentageLimit();
    if (percentageLimit != null) {
      AnalyticsUtils.convertToAltFieldName(percentageLimit::getField,
                                           percentageLimit::setField,
                                           fieldNames);
      convertToAltFieldName(percentageLimit.getAggregation(), fieldNames);
    }
    return filter;
  }

  private void convertToAltFieldName(AnalyticsPercentageItemFilter valueFilter, Set<String> fieldNames) {
    if (valueFilter != null) {
      AnalyticsAggregation aggregation = valueFilter.getYAxisAggregation();
      if (aggregation != null) {
        AnalyticsUtils.convertToAltFieldName(aggregation::getField,
                                             aggregation::setField,
                                             fieldNames);
      }
      List<AnalyticsFieldFilter> filters = valueFilter.getFilters();
      if (CollectionUtils.isNotEmpty(filters)) {
        for (AnalyticsFieldFilter analyticsFilter : filters) {
          AnalyticsUtils.convertToAltFieldName(analyticsFilter::getField,
                                               analyticsFilter::setField,
                                               fieldNames);
        }
      }
    }
  }

}
