package com.atlassian.stash.internal.user;

import com.atlassian.bitbucket.user.*;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Date;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * Implements {@link DetailedUser} by delegating all {@link ApplicationUser ApplicationUser} interface
 * methods to a wrapped {@link InternalApplicationUser} and adding directory-related properties locally.
 *
 * @since 2.0
 */
public class InternalDetailedUser implements DetailedUser {

    private final InternalApplicationUser delegate;
    private final String directoryName;
    private final boolean deletable;
    private final long lastAuthenticationTimestamp;
    private final boolean mutableDetails;
    private final boolean mutableGroups;

    private InternalDetailedUser(Builder builder) {
        delegate = builder.delegate;
        deletable = builder.deletable;
        directoryName = builder.directoryName;
        lastAuthenticationTimestamp = builder.lastAuthenticationTimestamp == null ?
                -1L :
                builder.lastAuthenticationTimestamp.getTime();
        mutableDetails = builder.mutableDetails;
        mutableGroups = builder.mutableGroups;
    }

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

    @Override
    @SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
    public boolean equals(Object o) {
        return ApplicationUserEquality.equals(this, o);
    }

    public InternalApplicationUser getDelegate() {
        return delegate;
    }

    public String getDirectoryName() {
        return directoryName;
    }

    @Override
    @Nonnull
    public String getDisplayName() {
        return delegate.getDisplayName();
    }

    @Override
    public String getEmailAddress() {
        return delegate.getEmailAddress();
    }

    @Override
    public int getId() {
        return delegate.getId();
    }

    @Override
    public Date getLastAuthenticationTimestamp() {
        return lastAuthenticationTimestamp == -1L ? null : new Date(lastAuthenticationTimestamp);
    }

    @Nonnull
    @Override
    public String getName() {
        return delegate.getName();
    }

    @Nonnull
    @Override
    public String getSlug() {
        return delegate.getSlug();
    }

    @Nonnull
    @Override
    public UserType getType() {
        return delegate.getType();
    }

    @Override
    public int hashCode() {
        return ApplicationUserEquality.hashCode(this);
    }

    @Override
    public boolean isActive() {
        return delegate.isActive();
    }

    @Override
    public boolean isDeletable() {
        return deletable;
    }

    @Override
    public boolean isMutableDetails() {
        return mutableDetails;
    }

    @Override
    public boolean isMutableGroups() {
        return mutableGroups;
    }

    public static class Builder {

        private InternalApplicationUser delegate;
        private boolean deletable;
        private String directoryName;
        private Date lastAuthenticationTimestamp;
        private boolean mutableDetails;
        private boolean mutableGroups;

        public Builder(InternalApplicationUser user) {
            delegate = checkNotNull(user, "user");
        }

        public Builder(InternalDetailedUser user) {
            delegate = checkNotNull(user, "user").delegate;
            directoryName = user.getDirectoryName();
            mutableDetails = user.isMutableDetails();
            mutableGroups = user.isMutableGroups();
        }

        @Nonnull
        public InternalDetailedUser build() {
            return new InternalDetailedUser(this);
        }

        @Nonnull
        public Builder deletable(boolean value) {
            deletable = value;

            return this;
        }

        @Nonnull
        public Builder directoryName(String value) {
            directoryName = checkNotNull(value, "value");

            return this;
        }

        @Nonnull
        public Builder lastAuthenticationTimestamp(@Nullable Date value) {
            lastAuthenticationTimestamp = value;

            return this;
        }

        @Nonnull
        public Builder mutableDetails(boolean value) {
            mutableDetails = value;

            return this;
        }

        @Nonnull
        public Builder mutableGroups(boolean value) {
            mutableGroups = value;

            return this;
        }
    }
}
