package com.bonus.canteen.core.config;

import cn.hutool.core.codec.Base64Decoder;
import com.google.common.collect.Sets;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Set;

@RefreshScope
@Component
@ConfigurationProperties(
   prefix = "secure"
)
public class SecureProperties {
   public static final String PREFIX = "secure";
   private boolean enabled = true;
   private boolean prohibitUnannotatedHandler = false;
   private String tokenSymbol = "X-Token";
   private String permissionKey = "secure:pms";
   private long permissionTTL = 7200L;
   private long expireAfter = 7200L;
   private ServerStore server = new ServerStore();
   private Security security = new Security();
   private MdcLogParameter mdc = new MdcLogParameter();

   public boolean isEnabled() {
      return this.enabled;
   }

   public boolean isProhibitUnannotatedHandler() {
      return this.prohibitUnannotatedHandler;
   }

   public String getTokenSymbol() {
      return this.tokenSymbol;
   }

   public String getPermissionKey() {
      return this.permissionKey;
   }

   public long getPermissionTTL() {
      return this.permissionTTL;
   }

   public long getExpireAfter() {
      return this.expireAfter;
   }

   public ServerStore getServer() {
      return this.server;
   }

   public Security getSecurity() {
      return this.security;
   }

   public MdcLogParameter getMdc() {
      return this.mdc;
   }

   public void setEnabled(final boolean enabled) {
      this.enabled = enabled;
   }

   public void setProhibitUnannotatedHandler(final boolean prohibitUnannotatedHandler) {
      this.prohibitUnannotatedHandler = prohibitUnannotatedHandler;
   }

   public void setTokenSymbol(final String tokenSymbol) {
      this.tokenSymbol = tokenSymbol;
   }

   public void setPermissionKey(final String permissionKey) {
      this.permissionKey = permissionKey;
   }

   public void setPermissionTTL(final long permissionTTL) {
      this.permissionTTL = permissionTTL;
   }

   public void setExpireAfter(final long expireAfter) {
      this.expireAfter = expireAfter;
   }

   public void setServer(final ServerStore server) {
      this.server = server;
   }

   public void setSecurity(final Security security) {
      this.security = security;
   }

   public void setMdc(final MdcLogParameter mdc) {
      this.mdc = mdc;
   }

   public static class ServerStore {
      private String storeKey = "secure:token";
      private String subjectRefTokenKey = "secure:subject-token";
      private long ttl = 14400L;

      public String getStoreKey() {
         return this.storeKey;
      }

      public String getSubjectRefTokenKey() {
         return this.subjectRefTokenKey;
      }

      public long getTtl() {
         return this.ttl;
      }

      public void setStoreKey(final String storeKey) {
         this.storeKey = storeKey;
      }

      public void setSubjectRefTokenKey(final String subjectRefTokenKey) {
         this.subjectRefTokenKey = subjectRefTokenKey;
      }

      public void setTtl(final long ttl) {
         this.ttl = ttl;
      }
   }

   public static class Security {
      private String encryptUriPrefix = "/security";
      private String keyExchangePath = "/exchange/key";
      private String publicKeyExchangePath = "/exchange/public-key";
      private Set<String> ignoredUri = Sets.newHashSet();
      private String requestBodySignParamName = "body";
      private String clientKeySignParamName = "clientKey";
      private Set<String> addonSignHeaderPrefix = Sets.newHashSet(new String[]{"X-Security-Ext"});
      private Set<String> tokenHeaderNames = Sets.newHashSet(new String[]{"X-Security-Token", "X-Security-Tenant-Id", "X-Security-Sn"});
      private String tokenSignHeaderName = "X-Security-Token-Sign";
      private String serverKeySignParamName = "serverKey";
      private String serverSm4Key = "McaCOPft5/J3bUG4pdVjhg==";
      private byte[] serverSm4KeyBytes;
      private String serverSm2Key;
      private byte[] serverSm2KeyBytes;
      private String clientSm2Key;
      private byte[] clientSm2KeyBytes;
      private String timestampHeaderName;
      private String nonceHeaderName;
      private String signHeaderName;
      private String serverEncryptedClientKeyHeaderName;
      private long maxWindowSeconds;
      private String playKey;

      public void setServerSm4Key(String serverSm4Key) {
         this.serverSm4Key = serverSm4Key;
         this.serverSm4KeyBytes = Base64Decoder.decode(serverSm4Key);
      }

      public Security() {
         this.serverSm4KeyBytes = Base64Decoder.decode(this.serverSm4Key);
         this.serverSm2Key = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgCtqk5Jj7pPWh91d9mPA4Kd7fOfzBULrnAERNDV+4XBCgCgYIKoEcz1UBgi2hRANCAARykhB6sXHWTbB60Pr+laPqEP5JBRpEcySONKKP5Q03o/g3OpnQXc7aVMdLUxL8wD1wQHEu4KHmHQr7jvVt0rkM";
         this.serverSm2KeyBytes = Base64Decoder.decode(this.serverSm2Key);
         this.clientSm2Key = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEcpIQerFx1k2wetD6/pWj6hD+SQUaRHMkjjSij+UNN6P4NzqZ0F3O2lTHS1MS/MA9cEBxLuCh5h0K+471bdK5DA==";
         this.clientSm2KeyBytes = Base64Decoder.decode(this.serverSm2Key);
         this.timestampHeaderName = "X-Security-Timestamp";
         this.nonceHeaderName = "X-Security-Nonce";
         this.signHeaderName = "X-Security-Sign";
         this.serverEncryptedClientKeyHeaderName = "X-Security-Server-Encrypted-Client-Key";
         this.maxWindowSeconds = 90L;
         this.playKey = "__play:";
      }

      public String getEncryptUriPrefix() {
         return this.encryptUriPrefix;
      }

      public String getKeyExchangePath() {
         return this.keyExchangePath;
      }

      public String getPublicKeyExchangePath() {
         return this.publicKeyExchangePath;
      }

      public Set<String> getIgnoredUri() {
         return this.ignoredUri;
      }

      public String getRequestBodySignParamName() {
         return this.requestBodySignParamName;
      }

      public String getClientKeySignParamName() {
         return this.clientKeySignParamName;
      }

      public Set<String> getAddonSignHeaderPrefix() {
         return this.addonSignHeaderPrefix;
      }

      public Set<String> getTokenHeaderNames() {
         return this.tokenHeaderNames;
      }

      public String getTokenSignHeaderName() {
         return this.tokenSignHeaderName;
      }

      public String getServerKeySignParamName() {
         return this.serverKeySignParamName;
      }

      public String getServerSm4Key() {
         return this.serverSm4Key;
      }

      public byte[] getServerSm4KeyBytes() {
         return this.serverSm4KeyBytes;
      }

      public String getServerSm2Key() {
         return this.serverSm2Key;
      }

      public byte[] getServerSm2KeyBytes() {
         return this.serverSm2KeyBytes;
      }

      public String getClientSm2Key() {
         return this.clientSm2Key;
      }

      public byte[] getClientSm2KeyBytes() {
         return this.clientSm2KeyBytes;
      }

      public String getTimestampHeaderName() {
         return this.timestampHeaderName;
      }

      public String getNonceHeaderName() {
         return this.nonceHeaderName;
      }

      public String getSignHeaderName() {
         return this.signHeaderName;
      }

      public String getServerEncryptedClientKeyHeaderName() {
         return this.serverEncryptedClientKeyHeaderName;
      }

      public long getMaxWindowSeconds() {
         return this.maxWindowSeconds;
      }

      public String getPlayKey() {
         return this.playKey;
      }

      public void setEncryptUriPrefix(final String encryptUriPrefix) {
         this.encryptUriPrefix = encryptUriPrefix;
      }

      public void setKeyExchangePath(final String keyExchangePath) {
         this.keyExchangePath = keyExchangePath;
      }

      public void setPublicKeyExchangePath(final String publicKeyExchangePath) {
         this.publicKeyExchangePath = publicKeyExchangePath;
      }

      public void setIgnoredUri(final Set<String> ignoredUri) {
         this.ignoredUri = ignoredUri;
      }

      public void setRequestBodySignParamName(final String requestBodySignParamName) {
         this.requestBodySignParamName = requestBodySignParamName;
      }

      public void setClientKeySignParamName(final String clientKeySignParamName) {
         this.clientKeySignParamName = clientKeySignParamName;
      }

      public void setAddonSignHeaderPrefix(final Set<String> addonSignHeaderPrefix) {
         this.addonSignHeaderPrefix = addonSignHeaderPrefix;
      }

      public void setTokenHeaderNames(final Set<String> tokenHeaderNames) {
         this.tokenHeaderNames = tokenHeaderNames;
      }

      public void setTokenSignHeaderName(final String tokenSignHeaderName) {
         this.tokenSignHeaderName = tokenSignHeaderName;
      }

      public void setServerKeySignParamName(final String serverKeySignParamName) {
         this.serverKeySignParamName = serverKeySignParamName;
      }

      public void setServerSm4KeyBytes(final byte[] serverSm4KeyBytes) {
         this.serverSm4KeyBytes = serverSm4KeyBytes;
      }

      public void setServerSm2Key(final String serverSm2Key) {
         this.serverSm2Key = serverSm2Key;
      }

      public void setServerSm2KeyBytes(final byte[] serverSm2KeyBytes) {
         this.serverSm2KeyBytes = serverSm2KeyBytes;
      }

      public void setClientSm2Key(final String clientSm2Key) {
         this.clientSm2Key = clientSm2Key;
      }

      public void setClientSm2KeyBytes(final byte[] clientSm2KeyBytes) {
         this.clientSm2KeyBytes = clientSm2KeyBytes;
      }

      public void setTimestampHeaderName(final String timestampHeaderName) {
         this.timestampHeaderName = timestampHeaderName;
      }

      public void setNonceHeaderName(final String nonceHeaderName) {
         this.nonceHeaderName = nonceHeaderName;
      }

      public void setSignHeaderName(final String signHeaderName) {
         this.signHeaderName = signHeaderName;
      }

      public void setServerEncryptedClientKeyHeaderName(final String serverEncryptedClientKeyHeaderName) {
         this.serverEncryptedClientKeyHeaderName = serverEncryptedClientKeyHeaderName;
      }

      public void setMaxWindowSeconds(final long maxWindowSeconds) {
         this.maxWindowSeconds = maxWindowSeconds;
      }

      public void setPlayKey(final String playKey) {
         this.playKey = playKey;
      }

   }

   public static class MdcLogParameter {
      private String subjectId = "x-id";
      private String subjectName = "x-name";

      public String getSubjectId() {
         return this.subjectId;
      }

      public String getSubjectName() {
         return this.subjectName;
      }

      public void setSubjectId(final String subjectId) {
         this.subjectId = subjectId;
      }

      public void setSubjectName(final String subjectName) {
         this.subjectName = subjectName;
      }
   }
}
