/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.facebook.presto.mongodb;

import com.facebook.presto.spi.block.SortOrder;
import com.google.common.collect.ImmutableList;
import com.mongodb.client.ListIndexesIterable;
import org.bson.Document;

import java.util.List;
import java.util.Optional;

import static com.google.common.base.Preconditions.checkState;
import static java.util.Objects.requireNonNull;

public class MongoIndex
{
    private final String name;
    private final List<MongodbIndexKey> keys;
    private final boolean unique;

    public static List<MongoIndex> parse(ListIndexesIterable<Document> indexes)
    {
        ImmutableList.Builder<MongoIndex> builder = ImmutableList.builder();
        for (Document index : indexes) {
            // TODO: v, ns, sparse fields
            Document key = (Document) index.get("key");
            String name = index.getString("name");
            boolean unique = index.getBoolean("unique", false);

            if (key.containsKey("_fts")) { // Full Text Search
                continue;
            }
            builder.add(new MongoIndex(name, parseKey(key), unique));
        }

        return builder.build();
    }

    private static List<MongodbIndexKey> parseKey(Document key)
    {
        ImmutableList.Builder<MongodbIndexKey> builder = ImmutableList.builder();

        for (String name : key.keySet()) {
            Object value = key.get(name);
            if (value instanceof Number) {
                int order = ((Number) value).intValue();
                checkState(order == 1 || order == -1, "Unknown index sort order");
                builder.add(new MongodbIndexKey(name, order == 1 ? SortOrder.ASC_NULLS_LAST : SortOrder.DESC_NULLS_LAST));
            }
            else if (value instanceof String) {
                builder.add(new MongodbIndexKey(name, (String) value));
            }
            else {
                throw new UnsupportedOperationException("Unknown index type: " + value.toString());
            }
        }

        return builder.build();
    }

    public MongoIndex(String name, List<MongodbIndexKey> keys, boolean unique)
    {
        this.name = name;
        this.keys = keys;
        this.unique = unique;
    }

    public String getName()
    {
        return name;
    }

    public List<MongodbIndexKey> getKeys()
    {
        return keys;
    }

    public boolean isUnique()
    {
        return unique;
    }

    public static class MongodbIndexKey
    {
        private final String name;
        private final Optional<SortOrder> sortOrder;
        private final Optional<String> type;

        public MongodbIndexKey(String name, SortOrder sortOrder)
        {
            this(name, Optional.of(sortOrder), Optional.empty());
        }

        public MongodbIndexKey(String name, String type)
        {
            this(name, Optional.empty(), Optional.of(type));
        }

        public MongodbIndexKey(String name, Optional<SortOrder> sortOrder, Optional<String> type)
        {
            this.name = requireNonNull(name, "name is null");
            this.sortOrder = sortOrder;
            this.type = type;
        }

        public String getName()
        {
            return name;
        }

        public Optional<SortOrder> getSortOrder()
        {
            return sortOrder;
        }

        public Optional<String> getType()
        {
            return type;
        }
    }
}
