/*
 * This file is part of the Meeds project (https://meeds.io/).
 * Copyright (C) 2020 - 2022 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.tenant.provisioning.web.websocket;

import static io.meeds.tenant.provisioning.service.TenantProvisioningService.DEED_EVENT_TENANT_CANCEL_COMMAND;
import static io.meeds.tenant.provisioning.service.TenantProvisioningService.DEED_EVENT_TENANT_COMPLETED_COMMAND;
import static io.meeds.tenant.provisioning.service.TenantProvisioningService.DEED_EVENT_TENANT_START_COMMAND_CREATED;
import static io.meeds.tenant.provisioning.service.TenantProvisioningService.DEED_EVENT_TENANT_STOP_COMMAND_CREATED;
import static io.meeds.tenant.provisioning.web.rest.utils.EntityMapper.toJsonString;
import static io.meeds.tenant.provisioning.web.rest.utils.EntityMapper.toWebSocketDTO;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;

import org.apache.commons.collections.CollectionUtils;
import org.mortbay.cometd.continuation.EXoContinuationBayeux;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import org.exoplatform.container.PortalContainer;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.ws.frameworks.cometd.ContinuationService;

import io.meeds.deeds.blockchain.BlockchainConfigurationProperties;
import io.meeds.deeds.elasticsearch.model.DeedTenant;
import io.meeds.deeds.listener.EventListener;
import io.meeds.tenant.provisioning.TenantProvisioningConfiguration;
import io.meeds.tenant.provisioning.service.TenantProvisioningService;
import io.meeds.tenant.provisioning.web.model.DeedTenantProvisioningWebSocket;

@Component
public class TenantProvisioningWebSocketService implements EventListener<DeedTenant> {

  public static final String                COMETD_CHANNEL   = "/Application/TenantProvisioning";

  public static final String                LISTENER_NAME    = "TenantProvisioningWebSocket";

  private static final List<String>         SUPPORTED_EVENTS = Arrays.asList(DEED_EVENT_TENANT_CANCEL_COMMAND,
                                                                             DEED_EVENT_TENANT_COMPLETED_COMMAND,
                                                                             DEED_EVENT_TENANT_START_COMMAND_CREATED,
                                                                             DEED_EVENT_TENANT_STOP_COMMAND_CREATED);

  private static final Log                  LOG              = ExoLogger.getLogger(TenantProvisioningWebSocketService.class);

  @Autowired
  private TenantProvisioningConfiguration   provisioningConfiguration;

  @Autowired
  private BlockchainConfigurationProperties blockchainProperties;

  @Autowired
  private TenantProvisioningService         tenantProvisioningService;

  private EXoContinuationBayeux             continuationBayeux;

  private ContinuationService               continuationService;

  @Override
  public void onEvent(String eventName, DeedTenant deedTenant) {
    DeedTenantProvisioningWebSocket deedTenantProvisioning = toWebSocketDTO(eventName,
                                                                            deedTenant,
                                                                            provisioningConfiguration.getEtherscanPrefix(),
                                                                            blockchainProperties.getDeedAddress());
    Set<String> connectedUserIds = getContinuationBayeux().getConnectedUserIds();
    Set<String> managers = tenantProvisioningService.getManagers();
    @SuppressWarnings("unchecked")
    Collection<String> usersToSendTo = CollectionUtils.intersection(managers, connectedUserIds);
    if (CollectionUtils.isNotEmpty(usersToSendTo)) {
      String message = toJsonString(deedTenantProvisioning);
      CompletableFuture.runAsync(() -> usersToSendTo.forEach(manager -> {
        try {
          getContinuationService().sendMessage(manager, COMETD_CHANNEL, message);
        } catch (Exception e) {
          LOG.warn("Error sending WebSocket message for user {} with message {}", manager, message, e);
        }
      }));
    }
  }

  @Override
  public String getName() {
    return LISTENER_NAME;
  }

  @Override
  public List<String> getSupportedEvents() {
    return SUPPORTED_EVENTS;
  }

  private EXoContinuationBayeux getContinuationBayeux() {
    if (continuationBayeux == null) {
      continuationBayeux = PortalContainer.getInstance().getComponentInstanceOfType(EXoContinuationBayeux.class);
    }
    return continuationBayeux;
  }

  private ContinuationService getContinuationService() {
    if (continuationService == null) {
      continuationService = PortalContainer.getInstance().getComponentInstanceOfType(ContinuationService.class);
    }
    return continuationService;
  }

}
