package cz.senslog.analytics.server.ws;


import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Consumer;

public final class ContentTypeHandler {

    private static Set<ContentType> parseContentTypes(String contentTypes) {
        if (contentTypes == null || contentTypes.isBlank()) {
            return Collections.emptySet();
        }
        String[] types = contentTypes.split(",");
        Set<ContentType> res = new HashSet<>(ContentType.values().length);
        for (String type : types) {
            String mediaType = type.split(";")[0];
            for (ContentType value : ContentType.values()) {
                if (mediaType.equalsIgnoreCase(value.contentType())) {
                    res.add(value);
                }
            }
        }
        return res;
    }

    public static ContentTypeHandler createWithSupportedTypes(ContentType... supportedTypes) {
        return new ContentTypeHandler(supportedTypes);
    }
    
    private final ContentType[] supportedTypes;

    private ContentTypeHandler(ContentType[] supportedTypes) {
        this.supportedTypes = supportedTypes;
    }
    
    public FluentHandler accept(String accept) {
        if (accept == null || accept.isBlank()) {
            throw new HttpIllegalArgumentException(400, "The Media Type is missing. Add 'Accept' attributeType in header.");
        }

        Set<ContentType> parsedTypes = parseContentTypes(accept);
        Set<ContentType> contentTypes = new HashSet<>();
        for (ContentType supportedType : supportedTypes) {
            if (parsedTypes.contains(supportedType)) {
                contentTypes.add(supportedType);
            }
        }
        if (contentTypes.isEmpty()) {
            throw new HttpIllegalArgumentException(415,
                    String.format("The Media Type '%s' is not supported. Supported are %s.", accept, Arrays.toString(ContentType.contentTypes(supportedTypes))));
        }
        return new FluentHandler(contentTypes);
    }

    public static final class FluentHandler {
        private final Set<ContentType> contentTypes;

        private FluentHandler(Set<ContentType> contentTypes) {
            this.contentTypes = contentTypes;
        }

        public FluentHandler handle(ContentType contentType, Consumer<ContentType> handler) {
            if (contentTypes.contains(contentType) && handler != null) {
                handler.accept(contentType);
            }
            return this;
        }
    }
}
