package ru.yandex.wmconsole.servantlet.notify;

import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.util.StringUtils;

import ru.yandex.common.framework.core.ServRequest;
import ru.yandex.common.framework.core.ServResponse;
import ru.yandex.common.framework.core.SimpleErrorInfo;
import ru.yandex.wmconsole.data.NotificationTypeEnum;
import ru.yandex.wmconsole.notifier.handler.NotificationHandler;
import ru.yandex.wmtools.common.error.UserException;
import ru.yandex.wmtools.common.servantlet.AbstractServantlet;

/**
 * @author Andrey Mima (amima@yandex-team.ru)
 */
public class InternalNotifyServantlet extends AbstractServantlet {
    private static final Logger log = LoggerFactory.getLogger(InternalNotifyServantlet.class);

    private static final String NOTIFICATION_TYPE_PARAM = "type";
    private static final String INTERNAL_HANDLE_HEADER = "header";
    private static final String INTERNAL_HANDLE_MESSAGE = "message";
    private static final String INTERNAL_MESSAGE_LANG = "message-lang";
    private static final String PARAM_HOST_LIST = "host_id";
    private static final String PARAM_MODE = "mode";
    private static final String PRODUCTION_MODE = "prod";

    private NotificationHandler notificationHandler;
    private boolean productionMode = false;

    @Override
    protected void doProcess(ServRequest req, ServResponse res) {
        log.info("Java internal request processing started");

        NotificationTypeEnum type;
        String typeParam = req.getParam(NOTIFICATION_TYPE_PARAM, true);

        if (typeParam == null) {
            log.warn("Invalid request parameter " + NOTIFICATION_TYPE_PARAM + " (is null)");
            res.addErrorInfo(new SimpleErrorInfo("Parameter '" + NOTIFICATION_TYPE_PARAM + "' is missing ot invalid"));
            return;
        }

        try {
            type = NotificationTypeEnum.R.fromValueOrNull(Integer.parseInt(typeParam));
        } catch (NumberFormatException e) {
            log.warn("Invalid request parameter " + NOTIFICATION_TYPE_PARAM + " (" + typeParam + ")");
            res.addErrorInfo(new SimpleErrorInfo("Parameter '" + NOTIFICATION_TYPE_PARAM + "' is missing or invalid"));
            return;
        }

        if (productionMode) {
            String mode;
            mode = req.getParam(PARAM_MODE);

            if ((mode == null) || (!PRODUCTION_MODE.equals(mode))) {
                log.warn("An attempt to use production servant without mode attribute");
                res.addErrorInfo(new SimpleErrorInfo("Parameter '" + PARAM_MODE + "' is missing ot invalid"));
                return;
            }
        }

        if (NotificationTypeEnum.HOST_VERIFIED.equals(type)) {
            final Map<String, String> params = new LinkedHashMap<String, String>(req.getParams());
            notificationHandler.handleInternalNotification(type, params);
            return;
        }

        if (NotificationTypeEnum.DELEGATION.equals(type)) {
            try {
                Long hostId = getRequiredLongParam(req, "host_id");
                Long userGotId = getRequiredLongParam(req, "user_got_id");
                Long userGaveId = getRequiredLongParam(req, "user_gave_id");
                Boolean mayRedelegate = getRequiredBooleanParam(req, "may_redelegate");
                Boolean givingDelegation = getRequiredBooleanParam(req, "giving_delegation");
                Date date = new Date(getRequiredLongParam(req, "date"));

                notificationHandler.internalHandleNotification(type,
                        hostId.toString(),
                        userGotId.toString(),
                        userGaveId.toString(),
                        mayRedelegate.toString(),
                        givingDelegation.toString(),
                        String.valueOf(date.getTime()));
            } catch (UserException e) {
                String error = "Internal notify: Required param missed.";
                log.error(error, e);
                res.addErrorInfo(new SimpleErrorInfo(error + " " + e.getMessage()));
            }
            return;
        }

        if (NotificationTypeEnum.HOST_STATUS_CHANGED.equals(type)) {
            // Передаем все параметры в виде Маp, так как некоторые параметры являются опциональными
            // и их удобнее анализировать в обработчике по именам.
            final Map<String, String> params = new LinkedHashMap<String, String>(req.getParams());
            notificationHandler.handleInternalNotification(type, params);

            return;
        }

        String header = req.getParam(INTERNAL_HANDLE_HEADER);
        String message = req.getParam(INTERNAL_HANDLE_MESSAGE);

        if ((type == NotificationTypeEnum.GLOBAL_MESSAGE || type == NotificationTypeEnum.PERSONAL_MESSAGE)) {
            final Map<String, String> params = new LinkedHashMap<String, String>(req.getParams());
            notificationHandler.handleInternalNotification(type, params);
        } else if (type == NotificationTypeEnum.HOST_OWNERS) {
            log.debug("Process NotificationTypeEnum.HOST_OWNERS case");
            Long[] hostList = getMultiParamLong(req, PARAM_HOST_LIST);
            // Для того, чтобы положить множественное значение в Map
            String csvHostList = StringUtils.arrayToCommaDelimitedString(hostList);
            final Map<String, String> params = new LinkedHashMap<String, String>(req.getParams());
            params.put(PARAM_HOST_LIST, csvHostList);
            notificationHandler.handleInternalNotification(NotificationTypeEnum.HOST_OWNERS, params);
        } else {
            log.warn("Invalid request parameter type");
            res.addErrorInfo(new SimpleErrorInfo("Invalid request parameters"));
        }
    }

    public void setProductionMode(String productionModeString) {
        productionMode = Boolean.valueOf(productionModeString);
    }

    @Required
    public void setNotificationHandler(NotificationHandler notificationHandler) {
        this.notificationHandler = notificationHandler;
    }
}
