package com.notononoto.teamcity.telegram.web;

import com.intellij.openapi.diagnostic.Logger;
import com.notononoto.teamcity.telegram.BotInfo;
import com.notononoto.teamcity.telegram.TelegramBotManager;
import com.notononoto.teamcity.telegram.config.TelegramSettings;
import com.notononoto.teamcity.telegram.config.TelegramSettingsManager;
import jetbrains.buildServer.controllers.*;
import jetbrains.buildServer.log.Loggers;
import jetbrains.buildServer.util.ExceptionUtil;
import jetbrains.buildServer.util.StringUtil;
import jetbrains.buildServer.web.openapi.WebControllerManager;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
 * Plugin servlet. Should handle writing of settings.
 */
public class TelegramSettingsController extends BaseFormXmlController {

  private static final Logger LOG = Loggers.SERVER;

  private static final String REQUEST_TYPE_PROP_NAME = "submitSettings";

  /** Settings manager */
  private final TelegramSettingsManager settingsManager;
  /** Bot manager */
  private final TelegramBotManager botManager;

  public TelegramSettingsController(@NotNull WebControllerManager webManager,
                                    @NotNull TelegramSettingsManager settingsManager,
                                    @NotNull TelegramBotManager botManager) {
    webManager.registerController("/telegram/notifierSettings.html", this);
    this.settingsManager = settingsManager;
    this.botManager = botManager;
  }

  @Override
  protected ModelAndView doGet(@NotNull HttpServletRequest request,
                               @NotNull HttpServletResponse response) {
    return null;
  }

  @Override
  protected void doPost(@NotNull HttpServletRequest request,
                        @NotNull HttpServletResponse response,
                        @NotNull Element xmlResponse) {

    String action = request.getParameter("action");
    if (action != null) {
      // We use action because we don't want to save another fields.
      // But this reset another form fields (javascript takes it).
      // It's very strange behaviour but this is Teamcity standard
      // behavior... Maybe in future we should change javascript code.
      boolean pause = "disable".equals(action);
      changePauseState(pause);
      return;
    }

    if (PublicKeyUtil.isPublicKeyExpired(request)) {
      PublicKeyUtil.writePublicKeyExpiredError(xmlResponse);
      return;
    }

    TelegramSettingsBean bean = new TelegramSettingsBean(settingsManager.getSettings());
    FormUtil.bindFromRequest(request, bean);
    if (isStoreInSessionRequest(request)) {
      XmlResponseUtil.writeFormModifiedIfNeeded(xmlResponse, bean);
    } else {
      ActionErrors errors = validate(bean);
      if (errors.hasNoErrors()) {
        if (isTestConnectionRequest(request)) {
          String testResult = testSettings(bean.toSettings());
          XmlResponseUtil.writeTestResult(xmlResponse, testResult);
        } else {
          settingsManager.saveConfiguration(bean.toSettings());
          FormUtil.removeAllFromSession(request.getSession(), bean.getClass());
          writeRedirect(xmlResponse, request.getContextPath() +
              "/admin/admin.html?item=" + TelegramSettingsPage.PLUGIN_NAME);
        }
      }
      writeErrors(xmlResponse, errors);
    }
  }

  private void changePauseState(boolean pause) {
    TelegramSettings oldSettings = settingsManager.getSettings();
    TelegramSettings newSettings = new TelegramSettings(oldSettings);
    newSettings.setPaused(pause);
    settingsManager.saveConfiguration(newSettings);
  }

  private String testSettings(@NotNull TelegramSettings settings) {
    try {
      BotInfo info = botManager.requestDescription(settings);
      if (info == null) {
        return "Can't find data about bot with requested token";
      }
      return "bot name: " + info.getName() + "\n" +
             "bot username: " + info.getUsername();
    } catch (Exception ex) {
      LOG.info("Can't send test message to Telegram: ", ex);
      return "Can't send test message to Telegram:\n" +
          ExceptionUtil.getDisplayMessage(ex);
    }
  }

  private ActionErrors validate(@NotNull TelegramSettingsBean settings) {
    ActionErrors errors = new ActionErrors();
    if (StringUtil.isEmptyOrSpaces(settings.getBotToken())) {
      errors.addError("emptyBotToken", "Bot token must not be empty");
    }
    if (settings.isUseProxy()) {
      if (StringUtils.isEmpty(settings.getProxyServer())) {
        errors.addError("emptyProxyServer", "Proxy server must not be empty");
      }
      if (StringUtils.isEmpty(settings.getProxyPort())) {
        errors.addError("emptyProxyPort", "Proxy port must not be empty");
      }
    }
    String port = settings.getProxyPort();
    if (!StringUtils.isEmpty(port) &&
        (!StringUtil.isNumber(port) || Integer.valueOf(port) < 1 || Integer.valueOf(port) > 65535)) {
      errors.addError("badProxyPort", "Proxy port must be integer between 1 and 65535");
    }
    return errors;
  }

  private boolean isStoreInSessionRequest(HttpServletRequest request) {
    return "storeInSession".equals(request.getParameter(REQUEST_TYPE_PROP_NAME));
  }

  private boolean isTestConnectionRequest(HttpServletRequest request) {
    return "testConnection".equals(request.getParameter(REQUEST_TYPE_PROP_NAME));
  }
}