package org.sagebionetworks.bridge.cache;

import java.util.List;
import java.util.Objects;

import org.sagebionetworks.bridge.models.accounts.Phone;
import org.sagebionetworks.bridge.models.accounts.SignIn;
import org.sagebionetworks.bridge.models.studies.StudyIdentifier;
import org.sagebionetworks.bridge.models.subpopulations.SubpopulationGuid;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;

/**
 * A utility to provide consistency, centralization, and type safety for the keys we use 
 * to store data in Redis. This makes it easier to determine which keys can be returned as 
 * part of the administrative API so we can keep PII data out of the cache keys we return.
 */
public final class CacheKeys {
    
    private static final Joiner COLON_JOINER = Joiner.on(":");
    private static final String[] PRIVATE_KEYS = new String[] {
            "session", "user", "request-info", "signInRequest", "phoneSignInRequest", "itp"};
    
    public final static boolean isPublic(String key) {
        for (String suffix : PRIVATE_KEYS) {
            if (key.endsWith(":"+suffix)) {
                return false;
            }
        }
        return true;
    }
    
    public final static class CacheKey {
        private final String key;
        private CacheKey(String... elements) {
            this.key = COLON_JOINER.join(elements);
        }
        @Override
        public String toString() {
            return key;
        }
        @Override
        public int hashCode() {
            return Objects.hashCode(key);
        }
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null || getClass() != obj.getClass())
                return false;
            CacheKey other = (CacheKey) obj;
            return Objects.equals(this.key, other.key);
        }
    }
    
    public static final CacheKey appConfigList(StudyIdentifier studyId) {
        return new CacheKey(studyId.getIdentifier(), "AppConfigList");
    }
    public static final CacheKey channelThrottling(String throttleType, String userId) {
        return new CacheKey(userId, throttleType, "channel-throttling");
    }
    public static final CacheKey emailSignInRequest(SignIn signIn) {
        return new CacheKey(signIn.getEmail(), signIn.getStudyId(), "signInRequest");
    }
    /** The email verification status from Amazon SES, which we cache for a short time. Not involved with 
     * verification of an individual's email address. So we do return it through the cache API.
     */
    public static final CacheKey emailVerification(String email) {
        return new CacheKey(email, "emailVerificationStatus");
    }
    public static final CacheKey itp(SubpopulationGuid subpopGuid, StudyIdentifier studyId, Phone phone) {
        return new CacheKey(subpopGuid.getGuid(), phone.getNumber(), studyId.getIdentifier(), "itp");
    }
    public static final CacheKey lock(String value, Class<?> clazz) {
        return new CacheKey(value, clazz.getCanonicalName(), "lock");
    }
    public static final CacheKey passwordResetForEmail(String sptoken, String studyId) {
        return new CacheKey(sptoken, studyId); // no type, not great
    }
    public static final CacheKey passwordResetForPhone(String sptoken, String studyId) { 
        return new CacheKey(sptoken, "phone", studyId); // no type, not great
    }
    public static final CacheKey phoneSignInRequest(SignIn signIn) {
        return new CacheKey(signIn.getPhone().getNumber(), signIn.getStudyId(),"phoneSignInRequest");
    }
    public static final CacheKey requestInfo(String userId) {
        return new CacheKey(userId, "request-info");
    }
    public static final CacheKey session(String sessionToken) {
        return new CacheKey(sessionToken, "session");
    }
    public static final CacheKey study(String studyId) {
        return new CacheKey(studyId, "study");
    }    
    public static final CacheKey subpop(SubpopulationGuid subpopGuid, StudyIdentifier studyId) {
        return new CacheKey(subpopGuid.getGuid(), studyId.getIdentifier(), "Subpopulation");
    }
    public static final CacheKey subpopList(StudyIdentifier studyId) {
        return new CacheKey(studyId.getIdentifier(), "SubpopulationList");
    }
    public static final CacheKey sessionByUserId(String userId) {
        return new CacheKey(userId, "session", "user");
    }
    public static final CacheKey verificationToken(String sptoken) {
        return new CacheKey(sptoken); // no type, not great
    }
    public static final CacheKey viewKey(Class<?> clazz, String... elements) {
        List<String> list = Lists.newArrayList(elements);
        list.add(clazz.getSimpleName());
        list.add("view");
        return new CacheKey(COLON_JOINER.join(list));
    }
}

@@ -837,22 +837,21 @@
 ring%5B%5D P
-RIVATE
+UBLIC
 _KEYS = 
@@ -877,90 +877,99 @@
     
-    %22session%22, %22user%22, %22request-info%22, %22signInRequest%22, %22phoneSignInRequest%22, %22itp
+%22AppConfigList%22, %22channel-throttling%22, %22lock%22, %22study%22, %22Subpopulation%22, %22SubpopulationList
 %22%7D;%0A
@@ -1062,14 +1062,13 @@
  : P
-RIVATE
+UBLIC
 _KEY
@@ -1131,36 +1131,35 @@
          return 
-fals
+tru
 e;%0A            %7D
@@ -1180,27 +1180,28 @@
      return 
-tru
+fals
 e;%0A    %7D%0A   

Switch to a whitelist of allowed keys in cache API; this is more secure and removes a lot of junk.