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

import java.util.*;
import java.util.stream.Collectors;

import model.FileModel;
import model.Filter;
import model.grid.GridDataExportFormat;
import model.grid.GridRow;
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.component.field.persist.filter.StaticFilterComponent;
import ru.micord.ervu.account_applications.component.model.Account;
import ru.micord.ervu.account_applications.component.model.Person;
import ru.micord.ervu.account_applications.component.model.dto.SearchRequest;
import ru.micord.ervu.account_applications.component.model.dto.SearchResponse;
import ru.micord.ervu.account_applications.dao.RecruitmentDao;
import ru.micord.ervu.account_applications.security.context.SecurityContext;
import ru.micord.ervu.account_applications.security.model.role.ErvuPermissionAuthority;
import ru.micord.ervu.account_applications.service.AccountFetchService;
import service.GridService;

import ru.cg.webbpm.modules.webkit.beans.Behavior;

/**
 * @author Adel Kalimullin
 */
@Service
public class AccountGridLoadService extends Behavior implements GridService {
  private static final String DOMAIN_IDS = "domainIds";
  private static final String DOMAIN_ID = "domainId";
  private final SecurityContext securityContext;
  private final AccountFetchService accountService;
  private final RecruitmentDao recruitmentDao;
  @Value("${ervu.security.role:#{null}}")
  private String ervuSecurityRole;

  public AccountGridLoadService(SecurityContext securityContext,
      AccountFetchService accountService,
      RecruitmentDao recruitmentDao) {
    this.securityContext = securityContext;
    this.accountService = accountService;
    this.recruitmentDao = recruitmentDao;
  }

  @Override
  public GridRows loadData(Integer offset, Integer limit, Filter[] filters,
      SortInfo[] sortInfos) {
    SearchRequest searchRequest = createLoadServiceRequest(offset, limit, filters);
    SearchResponse<Account> searchResponse  = accountService.fetchByFilter(searchRequest);

    List<GridRow> gridRows = searchResponse.getRecords() != null
                             ? convertToGridRows(searchResponse.getRecords())
                             : List.of();
    return new GridRows(gridRows);
  }

  @Override
  public GridRows loadDataWithRowCount(Integer offset, Integer limit, Filter[] filters,
      SortInfo[] sortInfos) {
    SearchRequest searchRequest = createLoadServiceRequest(offset, limit, filters);
    SearchResponse<Account> searchResponse = accountService.fetchByFilter(searchRequest);

    List<GridRow> gridRows = searchResponse.getRecords() != null
                      ? convertToGridRows(searchResponse.getRecords())
                      : List.of();
    return new GridRows(gridRows, searchResponse.getTotalRows());
  }

  @Override
  public FileModel exportData(String[] columnIdsToExport, GridDataExportFormat exportFormat,
      Filter[] filters, SortInfo[] sortInfo) {
    return GridService.super.exportData(columnIdsToExport, exportFormat, filters, sortInfo);
  }

  private List<GridRow> convertToGridRows(Set<Account> accounts) {
    List<GridRow> gridRows = new ArrayList<>();

      for (Account account : accounts) {
        GridRow gridRow = new GridRow();
        gridRow.put("row_uid", account.getId() != null ? account.getId() : "");
        gridRow.put("accountEnabled", !account.isBlocked());
        Person person = account.getPerson();
        if (person != null) {
          gridRow.put("login", person.getLogin());
          gridRow.put("snils", person.getSnils());
          gridRow.put("personEnabled", !person.isBlocked());
          gridRow.put("lastName", person.getLastName());
          gridRow.put("firstName", person.getFirstName());
          gridRow.put("middleName", person.getMiddleName());
        }

        if (account.getDomain() != null && account.getDomain().getName() != null) {
          gridRow.put("domainName", account.getDomain().getName());
        }

        gridRows.add(gridRow);
    }

    return gridRows;
  }

  private SearchRequest createLoadServiceRequest(Integer offset, Integer limit,
      Filter[] filters) {
    int page = (offset / limit) + 1;
    Map<String, Object> filterMap = new HashMap<>();
    Set<ErvuPermissionAuthority> permissions = securityContext.getPermissions();
    if (ervuSecurityRole == null
        || permissions.stream().noneMatch(permission -> permission.getAuthority().equals(ervuSecurityRole))) {
      List<String> domainIds = recruitmentDao.getRecruitmentIdsWithParentByDomainId(securityContext.getDomainId());
      filterMap.put(DOMAIN_IDS, domainIds.toArray());
    }
    if (filters != null && filters.length > 0) {
      filterMap.putAll(Arrays.stream(filters)
          .filter(filter -> filter.getFilterModels() != null && filter.getFilterModels().length > 0)
          .collect(Collectors.toMap(
              filter -> {
                String filterName = getScriptInObject(filter.componentGuid, StaticFilterComponent.class).name;
                if (DOMAIN_ID.equals(filterName)) {
                  return DOMAIN_IDS;
                }
                return filterName;
              },
              filter -> {
                String filterName = getScriptInObject(filter.componentGuid, StaticFilterComponent.class).name;
                Object filterValue = filter.getFilterModels()[0].value;
                if (DOMAIN_ID.equals(filterName)) {
                  return recruitmentDao.getRecruitmentIdsWithParentByDomainId(filterValue.toString()).toArray();
                }
                return filterValue;
              },
              (existing, replacement) -> replacement
          ))
      );
    }
    return new SearchRequest(filterMap, page, limit);
  }
}
