package ru.micord.ervu.account_applications.component.service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import component.field.persist.filter.FilterControl;
import model.Filter;
import model.grid.GridRows;
import model.grid.SortInfo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import ru.micord.ervu.account_applications.dao.RecruitmentDao;
import ru.micord.ervu.account_applications.security.model.role.ErvuPermissionAuthority;
import service.GridV2ServiceImpl;

import ru.cg.webbpm.modules.database.api.dao.option.LoadOptions;
import ru.cg.webbpm.modules.database.bean.annotation.LocalGraphSource;
import ru.cg.webbpm.modules.database.bean.entity_graph.EntityColumn;
import ru.cg.webbpm.modules.database.bean.filter.EntityFilter;
import ru.cg.webbpm.modules.database.bean.filter.FilterOperation;
import ru.micord.ervu.account_applications.security.context.SecurityContext;
import ru.cg.webbpm.modules.standard_annotations.editor.ObjectRef;
import ru.cg.webbpm.modules.standard_annotations.validation.NotNull;

/**
 * @author Adel Kalimullin
 */
@Service
public class RecruitmentGridService extends GridV2ServiceImpl {
  private final RecruitmentDao recruitmentDao;
  private final SecurityContext securityContext;
  @ObjectRef
  @NotNull
  public FilterControl filterControlRef;
  @LocalGraphSource(sourceFieldName = "loadDao")
  @NotNull
  public EntityColumn recruitmentColumn;
  @Value("${ervu.security.role:security_administrator}")
  private String ervuSecurityRole;

  public RecruitmentGridService(RecruitmentDao recruitmentDao, SecurityContext securityContext) {
    this.recruitmentDao = recruitmentDao;
    this.securityContext = securityContext;
  }

  @Override
  public GridRows loadData(Integer offset, Integer limit, Filter[] filters, SortInfo[] sortInfos) {
    Set<ErvuPermissionAuthority> permissions = securityContext.getPermissions();
    List<String> recruitmentIds;
    List<Filter> updatedFilters = new ArrayList<>(Arrays.asList(filters));
    Optional<Filter> recruitmentFilterOpt = findRecruitmentFilter(updatedFilters);
    if (ervuSecurityRole != null && permissions.stream().anyMatch(permission -> permission.getAuthority().equals(
        ervuSecurityRole))) {
      recruitmentIds = recruitmentFilterOpt.map(
              filter -> getChildRecruitmentIds(updatedFilters, filter))
          .orElseGet(this::getAllRecruitmentIds);
    }
    else {
      recruitmentIds = recruitmentFilterOpt.map(
              filter -> getChildRecruitmentIds(updatedFilters, filter))
          .orElseGet(this::getRecruitmentIdsForCurrentUser);
    }
    LoadOptions options = getOptions(offset, limit, updatedFilters.toArray(new Filter[0]),
        sortInfos
    );
    options.getEntityFilters().add(getEntityFilterForRecruitmentIds(recruitmentIds));

    return getGridRows(updatedFilters.toArray(new Filter[0]), options);
  }

  private Optional<Filter> findRecruitmentFilter(List<Filter> filters) {
    return filters.stream()
        .filter(filter -> filterControlRef.getObjectId().equals(filter.componentGuid))
        .findFirst();
  }

  private List<String> getChildRecruitmentIds(List<Filter> filters, Filter recruitmentFilter) {
    String selectedRecruitmentId = (String) recruitmentFilter.filterModels[0].getValue();
    filters.removeIf(filter -> filterControlRef.getObjectId().equals(filter.componentGuid));
    return recruitmentDao.getRecruitmentIdsWithParentByRecruitmentId(selectedRecruitmentId);
  }

  private List<String> getRecruitmentIdsForCurrentUser() {
    String domainId = securityContext.getDomainId();
    return recruitmentDao.getRecruitmentIdsWithParentByDomainId(domainId);
  }

  private EntityFilter getEntityFilterForRecruitmentIds(List<String> recruitmentIds) {
    return new EntityFilter(recruitmentIds, FilterOperation.IN, this.recruitmentColumn);
  }

  private List<String> getAllRecruitmentIds() {
    return recruitmentDao.getAllRecruitmentIds();
  }
}
