package com.atlassian.bitbucket.rest.user;

import com.atlassian.bitbucket.rest.annotation.JsonSurrogate;
import com.atlassian.bitbucket.rest.RestLinkedMapEntity;
import com.atlassian.bitbucket.rest.util.RestPage;
import com.atlassian.bitbucket.rest.util.RestRelatedLinks;
import com.atlassian.bitbucket.user.ApplicationUser;
import com.atlassian.bitbucket.user.ApplicationUserVisitor;
import com.atlassian.bitbucket.user.UserType;
import org.codehaus.jackson.map.annotate.JsonSerialize;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Map;
import java.util.function.Function;

import static com.atlassian.bitbucket.rest.util.RestDocUtils.pageOf;

@JsonSerialize
@JsonSurrogate(ApplicationUser.class)
public class RestApplicationUser extends RestPerson implements ApplicationUser {

    private static final String ACTIVE = "active";
    private static final String DISPLAY_NAME = "displayName";
    private static final String ID = "id";
    private static final String SLUG = "slug";
    private static final String TYPE = "type";

    public static final Function<ApplicationUser, RestApplicationUser> REST_TRANSFORM = RestApplicationUser::new;

    public RestApplicationUser(ApplicationUser user) {
        super(user);

        put(ID, user.getId());
        put(DISPLAY_NAME, user.getDisplayName());
        put(ACTIVE, user.isActive());
        put(SLUG, user.getSlug());
        put(TYPE, user.getType().name());
    }

    // for Jersey
    protected RestApplicationUser() {
    }

    /**
     * Constructs a new {@code RestApplicationUser} from the provided map of values.
     */
    protected RestApplicationUser(Map<String, Object> map) {
        super(map);
    }

    @Override
    public <T> T accept(@Nonnull ApplicationUserVisitor<T> visitor) {
        return visitor.visit(this);
    }

    @Nonnull
    @Override
    public String getDisplayName() {
        return getStringProperty(DISPLAY_NAME);
    }

    @Override
    public int getId() {
        return getIntProperty(ID);
    }

    @Nonnull
    @Override
    public String getSlug() {
        return getStringProperty(SLUG);
    }

    @Nonnull
    @Override
    public UserType getType() {
        return getEnumProperty(TYPE, UserType.class);
    }

    @Override
    public boolean isActive() {
        return getBoolProperty(ACTIVE);
    }

    public void setLinks(RestRelatedLinks links) {
        RestLinkedMapEntity.setLinks(this, links);
    }

    @Nullable
    @SuppressWarnings("unchecked")
    public static RestApplicationUser valueOf(@Nullable Object value) {
        if (value instanceof RestApplicationUser) {
            return (RestApplicationUser) value;
        } else if (value instanceof Map) {
            return new RestApplicationUser((Map) value);
        }

        return null;
    }

    // REST Documentation Examples
    public static final RestApplicationUser RESPONSE_EXAMPLE = new RestApplicationUser(ExampleDetailedUser.EXAMPLE);

    public static final RestPage<RestApplicationUser> PAGE_EXAMPLE = pageOf(RESPONSE_EXAMPLE);
}
