package ru.yandex.webmaster3.monitoring.solomon.trigger.actions;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.stream.Collectors;

import com.google.common.base.Strings;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;

import ru.yandex.solomon_api.model.SolomonAlertEvaluationState;
import ru.yandex.solomon_api.model.SolomonAlertEvaluationStatusDto;
import ru.yandex.webmaster3.core.WebmasterException;
import ru.yandex.webmaster3.core.http.Action;
import ru.yandex.webmaster3.core.http.ActionRequest;
import ru.yandex.webmaster3.core.http.ActionResponse;
import ru.yandex.webmaster3.core.http.ReadAction;
import ru.yandex.webmaster3.core.http.RequestQueryProperty;
import ru.yandex.webmaster3.core.http.WebmasterErrorResponse;
import ru.yandex.webmaster3.core.openapi.internal.ApiException;
import ru.yandex.webmaster3.core.util.RetryUtils;
import ru.yandex.webmaster3.monitoring.solomon.WebmasterTriggersService;
import ru.yandex.webmaster3.monitoring.solomon.api.SolomonControlApiV2Service;
import ru.yandex.webmaster3.monitoring.solomon.trigger.actions.GetAlertsStateAction.Request;
import ru.yandex.webmaster3.monitoring.solomon.trigger.actions.GetAlertsStateAction.Response;
import ru.yandex.webmaster3.monitoring.solomon.trigger.data.WebmasterTriggerInfo;

/**
 * Created by Oleg Bazdyrev on 07/08/2018.
 */
@ReadAction
public class GetAlertsStateAction extends Action<Request, Response> {
    private static final Logger log = LoggerFactory.getLogger(GetAlertsStateAction.class);

    private SolomonControlApiV2Service solomonControlApiV2Service;
    private WebmasterTriggersService webmasterTriggersService;
    private final ForkJoinPool pool = new ForkJoinPool(16);

    @Override
    public Response process(Request request) throws WebmasterException {
        List<String> triggerIds;
        if (Strings.isNullOrEmpty(request.getAlertId())) {
            triggerIds = webmasterTriggersService.listTriggers().stream().map(WebmasterTriggerInfo::getId)
                    .collect(Collectors.toList());
        } else {
            triggerIds = Collections.singletonList(request.getAlertId());
        }


        Map<String, SolomonAlertEvaluationStatusDto> statuses = new HashMap<>();

        pool.submit(() -> {
            triggerIds.parallelStream().forEach(triggerId -> {
                try {
                    RetryUtils.execute(RetryUtils.instantRetry(3), () -> {
                        SolomonAlertEvaluationState state = solomonControlApiV2Service.getAlertStatus(triggerId);
                        if (state != null
                                && state.getStatus() != null
                                && state.getStatus().getAnnotations() != null
                                && !state.getStatus().getAnnotations().isEmpty()) {
                            statuses.put(triggerId, state.getStatus());
                        }
                    });
                } catch (ApiException e) {
                    log.error("Failed to get alert status", e);
                    // ignore
                } catch (InterruptedException e) {
                    throw new WebmasterException("Interrupted",
                            new WebmasterErrorResponse.InternalUnknownErrorResponse(getClass(), null), e);
                }
            });
        }).join();

        return new Response(statuses);
    }

    @Required
    public void setSolomonControlApiV2Service(SolomonControlApiV2Service solomonControlApiV2Service) {
        this.solomonControlApiV2Service = solomonControlApiV2Service;
    }

    @Required
    public void setWebmasterTriggersService(WebmasterTriggersService webmasterTriggersService) {
        this.webmasterTriggersService = webmasterTriggersService;
    }

    public static class Request implements ActionRequest {

        private String alertId;

        public String getAlertId() {
            return alertId;
        }

        @RequestQueryProperty
        public void setAlertId(String alertId) {
            this.alertId = alertId;
        }
    }

    public static class Response implements ActionResponse.NormalResponse {

        private final Map<String, SolomonAlertEvaluationStatusDto> statuses;

        public Response(Map<String, SolomonAlertEvaluationStatusDto> statuses) {
            this.statuses = statuses;
        }

        public Map<String, SolomonAlertEvaluationStatusDto> getStatuses() {
            return statuses;
        }
    }

}
