package ru.yandex.autodoc.wmtools.errors;

import ru.yandex.autodoc.common.doc.annotation.Description;
import ru.yandex.autodoc.common.doc.annotation.ExampleConstructor;
import ru.yandex.autodoc.common.doc.annotation.JsonField;
import ru.yandex.autodoc.common.doc.params.ParamType;
import ru.yandex.autodoc.common.doc.annotation.Example;
import ru.yandex.wmtools.common.error.IUserProblem;
import ru.yandex.wmtools.common.error.UserException;

/**
 * @author avhaliullin
 */
@Description("Общие коды ошибок для всех сервисов")
public abstract class CommonUserException extends UserException {
    protected CommonUserException(IUserProblem problem, String message, Throwable cause) {
        super(problem, message, cause);
    }

    protected CommonUserException(IUserProblem problem, String message) {
        this(problem, message, null);
    }

    public static abstract class ParamException extends CommonUserException {
        @JsonField(name = "param", description = "Parameter name")
        public final String param;

        private ParamException(IUserProblem problem, String message, String param, Throwable cause) {
            super(problem, message, cause);
            this.param = param;
        }

        private ParamException(IUserProblem problem, String message, String param) {
            super(problem, message);
            this.param = param;
        }
    }

    public static abstract class ParamValueException extends ParamException {
        @JsonField(name = "value", description = "Parameter value")
        public final String value;

        private ParamValueException(IUserProblem problem, String message, String param, String value, Throwable cause) {
            super(problem, message, param, cause);
            this.value = value;
        }

        private ParamValueException(IUserProblem problem, String message, String param, String value) {
            super(problem, message, param);
            this.value = value;
        }
    }

    @Description("Отсутствует обязательный параметр")
    public static class RequiredParamMissedException extends ParamException {
        @Example
        public static final RequiredParamMissedException EXAMPLE = new RequiredParamMissedException("id");

        private RequiredParamMissedException(String param) {
            super(CommonUserProblem.REQUIRED_PARAM_MISSED, "Required param \"" + param + "\" missed", param);
        }
    }

    @Description("Неверное значение параметра")
    public static class IllegalParamValueException extends ParamValueException {
        @Example
        public static final IllegalParamValueException EXAMPLE = new IllegalParamValueException("hour", "25", "", null);

        public final UserException cause;

        private IllegalParamValueException(String param, String value, String extraInfo, UserException cause) {
            super(CommonUserProblem.ILLEGAL_PARAM_VALUE, "Param \"" + param + "\" has invalid value \"" + value + "\". " + extraInfo, param, value, cause);
            this.cause = cause;
        }
    }

    @Description("Неверный тип значения параметра")
    public static class IllegalValueTypeException extends ParamValueException {
        @Example
        public static final IllegalValueTypeException EXAMPLE = new IllegalValueTypeException("count", "three", ParamType.INTEGER);

        @JsonField(name = "type", description = "Expected parameter type")
        public final ParamType type;

        private IllegalValueTypeException(String param, String value, ParamType reqType) {
            super(CommonUserProblem.ILLEGAL_VALUE_TYPE, "Param \"" + param + "\" must be of type " + reqType.getName() + ", but has value \"" + value + "\". ", param, value);
            this.type = reqType;
        }
    }

    @Description("Слишком много значений передано в параметре (для мультипараметра или csv-параметров)")
    public static class TooManyValuesException extends ParamException {
        @Example
        public static final TooManyValuesException EXAMPLE = new TooManyValuesException("ip", 10, 20);

        @JsonField(name = "maxCount", description = "Max multiparam values count")
        public final int maxCount;
        @JsonField(name = "actualCount", description = "Actual multiparam values count")
        public final int actualCount;

        public TooManyValuesException(String param, int maxCount, int actualCount) {
            super(CommonUserProblem.TOO_MANY_VALUES, "There is too many values for param \"" + param + "\". Max values count: " + maxCount + ", actual values count: " + actualCount + ". ", param);
            this.maxCount = maxCount;
            this.actualCount = actualCount;
        }
    }

    @Description("Слишком мало значений передано в параметре (для мультипараметра или csv-параметров)")
    public static class TooFewValuesException extends ParamException {
        @Example
        public static final TooFewValuesException EXAMPLE = new TooFewValuesException("urls", 10, 8);

        @JsonField(name = "minCount", description = "Min multiparam values count")
        public final int minCount;
        @JsonField(name = "actualCount", description = "Actual multiparam values count")
        public final int actualCount;

        public TooFewValuesException(String param, int minCount, int actualCount) {
            super(CommonUserProblem.TOO_FEW_VALUES, "There is too few values for param \"" + param + "\". Min values count: " + minCount + ", actual values count: " + actualCount + ". ", param);
            this.minCount = minCount;
            this.actualCount = actualCount;
        }
    }

    @Description("Значение слишком длинное (слишком много символов)")
    public static class ValueTooLongException extends ParamValueException {
        @Example
        public static final ValueTooLongException EXAMPLE = new ValueTooLongException("short_name", "internationalization", 5);

        @JsonField(name = "maxLength", description = "Max param value length (chars count)")
        public final int maxLength;

        public ValueTooLongException(String param, String value, int maxLength) {
            super(CommonUserProblem.VALUE_TOO_LONG, "Value of param \"" + param + "\" is too long. Max length: " + maxLength + ", value: \"" + value + "\", actual length: " + value.length() + ". ", param, value);
            this.maxLength = maxLength;
        }
    }

    @Description("Значение слишком короткое (слишком мало символов)")
    public static class ValueTooShortException extends ParamValueException {
        @Example
        public static final ValueTooShortException EXAMPLE = new ValueTooShortException("description", "hello", 10);

        @JsonField(name = "minLength", description = "Min param value length (chars count)")
        public final int minLength;

        public ValueTooShortException(String param, String value, int minLength) {
            super(CommonUserProblem.VALUE_TOO_SHORT, "Value of param \"" + param + "\" is too short. Min length: " + minLength + ", value: \"" + value + "\", actual length: " + value.length() + ". ", param, value);
            this.minLength = minLength;
        }
    }

    @Description("В параметре передан некорректный URL")
    public static class MalformedURLException extends ParamValueException {
        @Example
        public static final MalformedURLException EXAMPLE = new MalformedURLException("url", "http://yandex", null);

        private MalformedURLException(String param, String url, UserException cause) {
            super(CommonUserProblem.MALFORMED_URLS, "Malformed url: \"" + url + "\"", param, url, cause);
        }
    }

    @Description("В параметре передан некорректный EMAIL")
    public static class MalformedEmailException extends ParamValueException {
        @Example
        public static final MalformedEmailException EXAMPLE = new MalformedEmailException("email", "avhaliullin%yandex-team.ru");

        private MalformedEmailException(String param, String email) {
            super(CommonUserProblem.MALFORMED_EMAIL, "Malformed email: \"" + email + "\"", param, email);
        }
    }

    @Description("В параметре передан email, не подтвержденный пользователем")
    public static class EmailNotVerifiedException extends ParamValueException {
        @Example
        public static final EmailNotVerifiedException EXAMPLE = new EmailNotVerifiedException("email", "avhaliullin@yandex-team.ru", 120160451);

        private EmailNotVerifiedException(String param, String email, long userId) {
            super(CommonUserProblem.EMAIL_NOT_VERIFIED, "Email \"" + email + "\" is not verified for user " + userId, param, email);
        }
    }

    @Description("Пользователь не зарегистрирован в сервисе")
    public static class NoSuchUserInServiceException extends CommonUserException {
        @ExampleConstructor
        public NoSuchUserInServiceException() {
            super(CommonUserProblem.NO_SUCH_USER_IN_SERVICE, "User not found in service");
        }
    }

    @Description("Требуется авторизация")
    public static class UserNotSignedInException extends CommonUserException {
        @ExampleConstructor
        public UserNotSignedInException() {
            super(CommonUserProblem.USER_NOT_SIGNED_IN, "User not signed in");
        }
    }

    @Description("Пользователь не принял лицензию")
    public static class UserHaventAcceptedLicenceException extends CommonUserException {
        @ExampleConstructor
        public UserHaventAcceptedLicenceException() {
            super(CommonUserProblem.USER_HAVENT_ACCEPTED_LICENCE, "User haven't accepted lcence");
        }
    }

    @Description("Пользователь не найден в паспорте")
    public static class UserNotFoundInPassportException extends CommonUserException {
        @Example
        public static final UserNotFoundInPassportException EXAMPLE = new UserNotFoundInPassportException("avhaliullin");

        @JsonField(name = "login", description = "Логин пользователя")
        public final String login;

        private UserNotFoundInPassportException(String login) {
            super(CommonUserProblem.USER_NOT_FOUND_IN_PASSPORT, "User " + login + " not found in passport");
            this.login = login;
        }
    }

    @Description("В параметре передан некорректный IP-адрес")
    public static class MalformedIPException extends ParamValueException {
        @Example
        public static final MalformedIPException EXAMPLE = new MalformedIPException("ip", "127.1");

        private MalformedIPException(String param, String ip) {
            super(CommonUserProblem.MALFORMED_IP, "Bad ip: \"" + ip + "\" in param \"" + param + "\"", param, ip);
        }
    }

    public static CommonUserException createRequiredParamMissed(String paramName) {
        return new RequiredParamMissedException(paramName);
    }

    public static CommonUserException createIllegalParamValue(String paramName, String paramValue) {
        return new IllegalParamValueException(paramName, paramValue, "", null);
    }

    public static CommonUserException createIllegalParamValue(String paramName, String paramValue, String extraInfo) {
        return new IllegalParamValueException(paramName, paramValue, extraInfo, null);
    }

    public static CommonUserException createIllegalParamValue(String paramName, String paramValue, String extraInfo, UserException cause) {
        return new IllegalParamValueException(paramName, paramValue, extraInfo, cause);
    }

    public static CommonUserException createIllegalValueType(String paramName, String paramValue, ParamType reqType) {
        return new IllegalValueTypeException(paramName, paramValue, reqType);
    }

    public static CommonUserException createTooManyValues(String paramName, int maxCount, int actualCount) {
        return new TooManyValuesException(paramName, maxCount, actualCount);
    }

    public static CommonUserException createTooFewValues(String paramName, int minCount, int actualCount) {
        return new TooFewValuesException(paramName, minCount, actualCount);
    }

    public static CommonUserException createValueTooLong(String paramName, String value, int maxLength) {
        return new ValueTooLongException(paramName, value, maxLength);
    }

    public static CommonUserException createValueTooShort(String paramName, String value, int minLength) {
        return new ValueTooShortException(paramName, value, minLength);
    }

    public static CommonUserException createMalformedUrl(String param, String url) {
        return createMalformedUrl(param, url, null);
    }

    public static CommonUserException createMalformedUrl(String param, String url, UserException cause) {
        return new MalformedURLException(param, url, cause);
    }

    public static CommonUserException createMalformedEmail(String param, String email) {
        return new MalformedEmailException(param, email);
    }

    public static CommonUserException createMalformedIP(String param, String ip) {
        return new MalformedIPException(param, ip);
    }

    public static CommonUserException createEmailNotVerified(String param, String email, long userId) {
        return new EmailNotVerifiedException(param, email, userId);
    }

    public static CommonUserException createUserNotFoundInPassport(String login) {
        return new UserNotFoundInPassportException(login);
    }

    public static CommonUserException createNoSuchUserInService() {
        return new NoSuchUserInServiceException();
    }

    public static CommonUserException createUserNotSignedIn() {
        return new UserNotSignedInException();
    }

    public static CommonUserException createUserHaventAcceptedLicence() {
        return new UserHaventAcceptedLicenceException();
    }
}
