package ru.yandex.autodoc.common.doc.params;

import org.apache.commons.lang3.StringUtils;
import ru.yandex.autodoc.common.doc.DocUtils;
import ru.yandex.autodoc.common.out.json.JsonValueWriter;
import ru.yandex.autodoc.common.util.enums.IEnumResolver;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * @author avhaliullin
 */
public class ParamType {
    @Deprecated
    public static final ParamType INTEGER = new ParamType("integer");
    @Deprecated
    public static final ParamType STRING = new ParamType("string");
    @Deprecated
    public static final ParamType BOOLEAN = new ParamType("boolean");
    @Deprecated
    public static final ParamType JSON = new ParamType("JSON");
    @Deprecated
    public static final ParamType FLOAT = new ParamType("float");

    private final String name;

    public ParamType(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public String toString() {
        return name;
    }

    public int hashCode() {
        return name.hashCode();
    }

    public boolean equals(Object o) {
        return o != null && o instanceof ParamType && ((ParamType) o).getName().equals(name);
    }

    @Deprecated
    public static ParamType multi(ParamType type) {
        return new ParamType("multi param of " + type.getName());
    }

    @Deprecated
    public static ParamType array(ParamType type) {
        return new ParamType("array of " + type.getName());
    }

    @Deprecated
    public static ParamType separated(String delimiters) {
        return new ParamType("strings separated with: [" +
                delimiters.replace("\n", "\\n").replace("\r", "\\r").replace(" ", "\\s").replace("\t", "\\t") +
                "]");
    }

    @Deprecated
    public static ParamType color(boolean allowTransparent) {
        return new ParamType("color" + (allowTransparent ? " (with transparent)" : ""));
    }

    @Deprecated
    public static ParamType date(String template) {
        return new ParamType("date (" + template + ")");
    }

    @Deprecated
    public static ParamType date(DateFormat format) {
        if (format instanceof SimpleDateFormat) {
            return date(((SimpleDateFormat) format).toPattern());
        } else {
            return date(format.toString());
        }
    }

    @Deprecated
    public static DocumentedEnum enumForClass(Class<?> clazz) {
        if (!clazz.isEnum()) {
            throw new IllegalArgumentException("Class " + clazz.getCanonicalName() + " is not enum");
        }
        Object[] values = clazz.getEnumConstants();
        List<DocumentedEnum.Entry> entries = new ArrayList<>();
        List<String> plainValues = new ArrayList<>();
        for (Object o : values) {
            Enum<?> value = (Enum<?>) o;
            String description;
            try {
                description = DocUtils.getDescriptionForAnnotatedElement(clazz.getField(value.name()));
            } catch (NoSuchFieldException e) {
                throw new RuntimeException("Should never happen - can't get field  " + value.name() + " of enum " + clazz);
            }
            entries.add(new DocumentedEnum.Entry(value.name(), description));
            plainValues.add(o.toString());
        }
        return new DocumentedEnum(clazz.getSimpleName(), entries);
    }

    @Deprecated
    public static <T> ParamType enumName(IEnumResolver<T> resolver) {
        return new ParamType(STRING.getName() + ", one of: [" + resolver.join(resolver.listAll(), ", ") + "]");
    }

    @Deprecated
    public static ParamType stringOneOf(Collection<String> universe) {
        return new ParamType(STRING.getName() + ", one of: [" + StringUtils.join(universe, ", ") + "]");
    }

    @Deprecated
    public static ParamType json(JsonValueWriter format) {
        return new JsonParam(format);
    }

    @Deprecated
    public static class DocumentedEnum extends ParamType {
        public final List<Entry> universe;

        public DocumentedEnum(String name, List<Entry> universe) {
            super(name);
            this.universe = universe;
        }

        public static class Entry {
            public final String value;
            public final String description;

            public Entry(String value, String description) {
                this.value = value;
                this.description = description;
            }
        }
    }

    @Deprecated
    public static class JsonNodeType extends ParamType {

        public static final JsonNodeType INTEGER = new JsonNodeType("integer");
        public static final JsonNodeType STRING = new JsonNodeType("string");
        public static final JsonNodeType OBJECT = new JsonNodeType("object");
        public static final JsonNodeType ARRAY = new JsonNodeType("array");

        private JsonNodeType(String name) {
            super("JSON node - " + name + "");
        }

        public static <T> JsonNodeType enumName(IEnumResolver<T> universe) {
            return new JsonNodeType(ParamType.enumName(universe).getName());
        }

    }

    @Deprecated
    public static class JsonParam extends ParamType {
        public final JsonValueWriter format;

        public JsonParam(JsonValueWriter format) {
            super("JSON");
            this.format = format;
        }
    }
}
