package io.liveoak.ups.resource;

import java.util.Collection;
import java.util.LinkedList;
import java.util.UUID;

import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import io.liveoak.spi.RequestContext;
import io.liveoak.spi.security.SecurityContext;
import io.liveoak.spi.resource.SynchronousResource;
import io.liveoak.spi.resource.async.Resource;
import io.liveoak.spi.resource.async.Responder;
import io.liveoak.spi.state.ResourceState;
import io.liveoak.ups.Alias;

/**
 * @author <a href="mailto:mwringe@redhat.com">Matt Wringe</a>
 */
public class AliasesResource implements SynchronousResource {

    private UPSRootResource parent;
    private DBCollection collection;

    public static final String ID = "aliases";

    public AliasesResource(UPSRootResource parent, DBCollection collection) {
        this.parent = parent;
        this.collection = collection;
    }

    @Override
    public Resource parent() {
        return this.parent;
    }

    @Override
    public String id() {
        return this.ID;
    }

    @Override
    public void updateProperties(RequestContext ctx, ResourceState state, Responder responder) throws Exception {
        responder.updateNotSupported(this);
    }

    @Override
    public void delete(RequestContext ctx, Responder responder) throws Exception {
        responder.deleteNotSupported(this);
    }

    @Override
    public void createMember(RequestContext ctx, ResourceState state, Responder responder) throws Exception {
        SecurityContext sCtx = ctx.securityContext();
        String subjectId = null;

        if (state.id() != null) {
            responder.invalidRequest("An alias resources cannot set its own id. IDs are generated by the system.");
            return;
        }

        if (sCtx != null && sCtx.isAuthenticated()) {
            subjectId = sCtx.getSubject();

            //TODO: add in index to force subject to be a unique field
            DBObject dbObject = collection.findOne(new BasicDBObject("subject", subjectId));
            if (dbObject != null) {
                responder.resourceCreated(new AliasResource(this, Alias.create(dbObject)));
                return;
            }
        }

        // if we didn't find the userid in the list or the user is not authenticated, create a new alias
        DBObject newAlias = new BasicDBObject("_id", UUID.randomUUID().toString());
        if (subjectId != null) {
            newAlias.put("subject", subjectId);
        }
        collection.insert(newAlias);
        responder.resourceCreated(new AliasResource(this, Alias.create(newAlias)));
    }

    @Override
    public Collection<Resource> members(RequestContext ctx) throws Exception {
        LinkedList<Resource> members = new LinkedList<>();
        DBCursor cursor = collection.find();
        while (cursor.hasNext()) {
            members.add(new AliasResource(this, Alias.create(cursor.next())));
        }
        return members;
    }

    @Override
    public Resource member(RequestContext ctx, String id) throws Exception {
        DBObject dbObject = collection.findOne(new BasicDBObject("_id", id));
        if (dbObject != null) {
            return new AliasResource(this, Alias.create(dbObject));
        }
        return null;
    }

    public void saveAlias(Alias alias) {
        collection.save(alias.dbObject());
    }

    public void deleteAlias(String id) {
        DBObject dbObject = collection.findOne(new BasicDBObject("_id", id));
        if (dbObject != null) {
            collection.remove(dbObject);
        }
    }
}
