package ervu_business_metrics.service.processor.impl;

import java.sql.Timestamp;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import ervu_business_metrics.config.KafkaEnabledCondition;
import ervu_business_metrics.model.idm.AccountData;
import ervu_business_metrics.service.IdmDirectoriesDaoService;
import ervu_business_metrics.service.processor.DataProcessor;
import org.springframework.context.annotation.Conditional;
import org.springframework.stereotype.Component;
import ru.micord.webbpm.ervu.business_metrics.db_beans.idm_reconcile.tables.records.AccountRecord;
import ru.micord.webbpm.ervu.business_metrics.db_beans.idm_reconcile.tables.records.AccountRoleRecord;

/**
 * @author Adel Kalimullin
 */
@Component
@Conditional(KafkaEnabledCondition.class)
public class AccountDataProcessor implements DataProcessor<AccountData> {
  private final IdmDirectoriesDaoService idmDirectoriesDaoService;

  public AccountDataProcessor(IdmDirectoriesDaoService idmDirectoriesDaoService) {
    this.idmDirectoriesDaoService = idmDirectoriesDaoService;
  }

  @Override
  public void upsertData(List<AccountData> dataList) {
    List<AccountRecord> newAccountRecords = new ArrayList<>();
    List<AccountRecord> accountRecordsToUpdate = new ArrayList<>();
    List<AccountRoleRecord> newAccountRoleRecords = new ArrayList<>();
    List<String> accountsToDeleteRoles = new ArrayList<>();
    Set<String> existingIds = idmDirectoriesDaoService.getAccountIds();

    for (AccountData data : dataList) {
      AccountRecord record = idmDirectoriesDaoService.getAccountRecord();
      Timestamp modifiedAt = Timestamp.from(Instant.ofEpochMilli(data.getModified()));

      record.setId(data.getId());
      record.setVersion(data.getVersion());
      record.setSchema(data.getSchema());
      record.setModified(modifiedAt);
      record.setStart(data.getStart());
      record.setFinish(data.getFinish());
      record.setEnabled(data.isEnabled());
      record.setPosition(data.getPosition());
      record.setFio(data.getFio());
      record.setWorkMail(data.getWorkMail());
      record.setEsiaAccount(data.isEsiaAccount());
      if (data.getUserDomain() != null) {
        record.setDomainId(data.getUserDomain().getId());
      }

      if (existingIds.contains(data.getId())) {
        accountRecordsToUpdate.add(record);
        accountsToDeleteRoles.add(data.getId());
      }
      else {
        newAccountRecords.add(record);
      }

      if (data.getRoles() != null && !data.getRoles().isEmpty()) {
        addRolesForAccount(data, newAccountRoleRecords);
      }
    }

    if (!newAccountRecords.isEmpty()) {
      idmDirectoriesDaoService.insertAccountRecords(newAccountRecords);
    }

    if (!accountRecordsToUpdate.isEmpty()) {
      idmDirectoriesDaoService.updateAccountRecords(accountRecordsToUpdate);
    }

    if (!accountsToDeleteRoles.isEmpty()) {
      idmDirectoriesDaoService.deleteAccountRolesByAccountIds(accountsToDeleteRoles);
    }

    if (!newAccountRoleRecords.isEmpty()) {
      idmDirectoriesDaoService.insertAccountRoleRecords(newAccountRoleRecords);
    }
  }

  @Override
  public void deleteData(List<String> ids) {
    idmDirectoriesDaoService.deleteAccountsByIds(ids);
  }

  private void addRolesForAccount(AccountData data, List<AccountRoleRecord> accountRoleRecords) {
    Set<String> existingRoleIds = idmDirectoriesDaoService.getRoleIds();

    for (String roleId : data.getRoles()) {
      if (existingRoleIds.contains(roleId)) {
        AccountRoleRecord accountRoleRecord = idmDirectoriesDaoService.getAccountRoleRecord();
        accountRoleRecord.setAccountId(data.getId());
        accountRoleRecord.setRoleId(roleId);
        accountRoleRecords.add(accountRoleRecord);
      }
    }
  }
}
