package com.bonus.common.houqin.mq.rabbit;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ArrayUtil;
import com.google.common.collect.Maps;
import org.springframework.amqp.core.*;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.Binding.DestinationType;
import org.springframework.boot.autoconfigure.amqp.RabbitProperties;

import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;

public class RabbitPropertiesExt extends RabbitProperties {
   private Set<ExchangeProperties> exchange = new HashSet();
   private Set<ExchangeProperties> exchangeMore = new HashSet();
   private Set<QueueProperties> queue = new HashSet();
   private Set<QueueProperties> queueMore = new HashSet();
   private Set<BindingProperties> binding = new HashSet();
   private Set<BindingProperties> bindingMore = new HashSet();
   private String normalExchange = "amq.topic";
   private String delayedExchange = "delayed";
   private String txCheckTaskName = "_mqAskTaskHandler";
   private String retryQueue = "_retry";
   private boolean cleanNoneNamespaceQueue = false;
   private int managerPort = 15672;

   public Set<ExchangeProperties> getExchange() {
      return this.exchange;
   }

   public Set<ExchangeProperties> getExchangeMore() {
      return this.exchangeMore;
   }

   public Set<QueueProperties> getQueue() {
      return this.queue;
   }

   public Set<QueueProperties> getQueueMore() {
      return this.queueMore;
   }

   public Set<BindingProperties> getBinding() {
      return this.binding;
   }

   public Set<BindingProperties> getBindingMore() {
      return this.bindingMore;
   }

   public String getNormalExchange() {
      return this.normalExchange;
   }

   public String getDelayedExchange() {
      return this.delayedExchange;
   }

   public String getTxCheckTaskName() {
      return this.txCheckTaskName;
   }

   public String getRetryQueue() {
      return this.retryQueue;
   }

   public boolean isCleanNoneNamespaceQueue() {
      return this.cleanNoneNamespaceQueue;
   }

   public int getManagerPort() {
      return this.managerPort;
   }

   public void setExchange(final Set<ExchangeProperties> exchange) {
      this.exchange = exchange;
   }

   public void setExchangeMore(final Set<ExchangeProperties> exchangeMore) {
      this.exchangeMore = exchangeMore;
   }

   public void setQueue(final Set<QueueProperties> queue) {
      this.queue = queue;
   }

   public void setQueueMore(final Set<QueueProperties> queueMore) {
      this.queueMore = queueMore;
   }

   public void setBinding(final Set<BindingProperties> binding) {
      this.binding = binding;
   }

   public void setBindingMore(final Set<BindingProperties> bindingMore) {
      this.bindingMore = bindingMore;
   }

   public void setNormalExchange(final String normalExchange) {
      this.normalExchange = normalExchange;
   }

   public void setDelayedExchange(final String delayedExchange) {
      this.delayedExchange = delayedExchange;
   }

   public void setTxCheckTaskName(final String txCheckTaskName) {
      this.txCheckTaskName = txCheckTaskName;
   }

   public void setRetryQueue(final String retryQueue) {
      this.retryQueue = retryQueue;
   }

   public void setCleanNoneNamespaceQueue(final boolean cleanNoneNamespaceQueue) {
      this.cleanNoneNamespaceQueue = cleanNoneNamespaceQueue;
   }

   public void setManagerPort(final int managerPort) {
      this.managerPort = managerPort;
   }

   public String toString() {
      String var10000 = String.valueOf(this.getExchange());
      return "RabbitPropertiesExt(exchange=" + var10000 + ", exchangeMore=" + String.valueOf(this.getExchangeMore()) + ", queue=" + String.valueOf(this.getQueue()) + ", queueMore=" + String.valueOf(this.getQueueMore()) + ", binding=" + String.valueOf(this.getBinding()) + ", bindingMore=" + String.valueOf(this.getBindingMore()) + ", normalExchange=" + this.getNormalExchange() + ", delayedExchange=" + this.getDelayedExchange() + ", txCheckTaskName=" + this.getTxCheckTaskName() + ", retryQueue=" + this.getRetryQueue() + ", cleanNoneNamespaceQueue=" + this.isCleanNoneNamespaceQueue() + ", managerPort=" + this.getManagerPort() + ")";
   }

   public static class RabbitMessage {
      private String payload;
      private String id;
      private String exchange;
      private String routingKey;
      private Long delay;
      private LocalDateTime createTime;

      public RabbitMessage(String id, String payload, String exchange, String routingKey) {
         this.id = id;
         this.payload = payload;
         this.exchange = exchange;
         this.routingKey = routingKey;
      }

      public RabbitMessage() {
      }

      public String getPayload() {
         return this.payload;
      }

      public String getId() {
         return this.id;
      }

      public String getExchange() {
         return this.exchange;
      }

      public String getRoutingKey() {
         return this.routingKey;
      }

      public Long getDelay() {
         return this.delay;
      }

      public LocalDateTime getCreateTime() {
         return this.createTime;
      }

      public void setPayload(final String payload) {
         this.payload = payload;
      }

      public void setId(final String id) {
         this.id = id;
      }

      public void setExchange(final String exchange) {
         this.exchange = exchange;
      }

      public void setRoutingKey(final String routingKey) {
         this.routingKey = routingKey;
      }

      public void setDelay(final Long delay) {
         this.delay = delay;
      }

      public void setCreateTime(final LocalDateTime createTime) {
         this.createTime = createTime;
      }

   }

   public static class QueueProperties {
      public static final String NAMESPACE_KEY = "_namespace";
      private static final NamingStrategy namingStrategy;
      private String name;
      private boolean durable = true;
      private boolean exclusive;
      private boolean autoDelete;
      private Integer ttl;
      private Integer expires;
      private Integer maxLength;
      private Integer maxLengthBytes;
      private QueueBuilder.Overflow overflow;
      private String deadLetterExchange;
      private String deadLetterRoutingKey;
      private Integer maxPriority;
      private boolean lazy;
      private QueueBuilder.LeaderLocator leaderLocator;
      private boolean singleActiveConsumer;
      private boolean quorum = true;
      private boolean stream;
      private Integer deliveryLimit;
      private Map<String, Object> arguments;

      public QueueProperties(String name, String namespace) {
         this.name = name;
         if (this.arguments == null) {
            this.arguments = Maps.newHashMap();
         }

         this.arguments.put("_namespace", namespace);
      }

      public Queue buildQueue() {
         String actualName = CharSequenceUtil.isBlank(this.name) ? namingStrategy.generateName() : this.name;
         QueueBuilder builder = this.durable ? QueueBuilder.durable(actualName) : QueueBuilder.nonDurable(actualName);
         if (this.exclusive) {
            builder.exclusive();
         }

         if (this.autoDelete) {
            builder.autoDelete();
         }

         if (this.ttl != null) {
            builder.ttl(this.ttl);
         }

         if (this.expires != null) {
            builder.expires(this.expires);
         }

         if (this.maxLength != null) {
            builder.maxLength(this.maxLength);
         }

         if (this.maxLengthBytes != null) {
            builder.maxLengthBytes(this.maxLengthBytes);
         }

         if (this.overflow != null) {
            builder.overflow(this.overflow);
         }

         if (CharSequenceUtil.isNotBlank(this.deadLetterExchange)) {
            builder.deadLetterExchange(this.deadLetterExchange);
         }

         if (CharSequenceUtil.isNotBlank(this.deadLetterRoutingKey)) {
            builder.deadLetterExchange(this.deadLetterRoutingKey);
         }

         if (this.maxPriority != null) {
            builder.maxPriority(this.maxPriority);
         }

         if (this.lazy) {
            builder.lazy();
         }

         if (this.leaderLocator != null) {
            builder.leaderLocator(this.leaderLocator);
         }

         if (this.singleActiveConsumer) {
            builder.singleActiveConsumer();
         }

         if (this.quorum) {
            builder.quorum();
         }

         if (this.stream) {
            builder.stream();
         }

         if (this.deliveryLimit != null) {
            builder.deliveryLimit(this.deliveryLimit);
         }

         if (MapUtil.isNotEmpty(this.arguments)) {
            builder.withArguments(this.arguments);
         }

         return builder.build();
      }

      public String getName() {
         return this.name;
      }

      public boolean isDurable() {
         return this.durable;
      }

      public boolean isExclusive() {
         return this.exclusive;
      }

      public boolean isAutoDelete() {
         return this.autoDelete;
      }

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

      public Integer getExpires() {
         return this.expires;
      }

      public Integer getMaxLength() {
         return this.maxLength;
      }

      public Integer getMaxLengthBytes() {
         return this.maxLengthBytes;
      }

      public QueueBuilder.Overflow getOverflow() {
         return this.overflow;
      }

      public String getDeadLetterExchange() {
         return this.deadLetterExchange;
      }

      public String getDeadLetterRoutingKey() {
         return this.deadLetterRoutingKey;
      }

      public Integer getMaxPriority() {
         return this.maxPriority;
      }

      public boolean isLazy() {
         return this.lazy;
      }

      public QueueBuilder.LeaderLocator getLeaderLocator() {
         return this.leaderLocator;
      }

      public boolean isSingleActiveConsumer() {
         return this.singleActiveConsumer;
      }

      public boolean isQuorum() {
         return this.quorum;
      }

      public boolean isStream() {
         return this.stream;
      }

      public Integer getDeliveryLimit() {
         return this.deliveryLimit;
      }

      public Map<String, Object> getArguments() {
         return this.arguments;
      }

      public void setName(final String name) {
         this.name = name;
      }

      public void setDurable(final boolean durable) {
         this.durable = durable;
      }

      public void setExclusive(final boolean exclusive) {
         this.exclusive = exclusive;
      }

      public void setAutoDelete(final boolean autoDelete) {
         this.autoDelete = autoDelete;
      }

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

      public void setExpires(final Integer expires) {
         this.expires = expires;
      }

      public void setMaxLength(final Integer maxLength) {
         this.maxLength = maxLength;
      }

      public void setMaxLengthBytes(final Integer maxLengthBytes) {
         this.maxLengthBytes = maxLengthBytes;
      }

      public void setOverflow(final QueueBuilder.Overflow overflow) {
         this.overflow = overflow;
      }

      public void setDeadLetterExchange(final String deadLetterExchange) {
         this.deadLetterExchange = deadLetterExchange;
      }

      public void setDeadLetterRoutingKey(final String deadLetterRoutingKey) {
         this.deadLetterRoutingKey = deadLetterRoutingKey;
      }

      public void setMaxPriority(final Integer maxPriority) {
         this.maxPriority = maxPriority;
      }

      public void setLazy(final boolean lazy) {
         this.lazy = lazy;
      }

      public void setLeaderLocator(final QueueBuilder.LeaderLocator leaderLocator) {
         this.leaderLocator = leaderLocator;
      }

      public void setSingleActiveConsumer(final boolean singleActiveConsumer) {
         this.singleActiveConsumer = singleActiveConsumer;
      }

      public void setQuorum(final boolean quorum) {
         this.quorum = quorum;
      }

      public void setStream(final boolean stream) {
         this.stream = stream;
      }

      public void setDeliveryLimit(final Integer deliveryLimit) {
         this.deliveryLimit = deliveryLimit;
      }

      public void setArguments(final Map<String, Object> arguments) {
         this.arguments = arguments;
      }

      public QueueProperties() {
      }

      static {
         namingStrategy = Base64UrlNamingStrategy.DEFAULT;
      }
   }

   public static class ExchangeProperties {
      private static final Map<String, Function<String, ExchangeBuilder>> TYPE_CREATOR = new HashMap();
      private String name;
      private String type = "topic";
      private boolean durable = true;
      private boolean autoDelete;
      private boolean internal;
      private boolean delayed = true;
      private boolean ignoreDeclarationExceptions;
      private boolean declare = true;
      private Object[] declaringAdmins;
      private Map<String, Object> arguments;

      public ExchangeProperties(String name) {
         this.name = name;
      }

      public Exchange buildExchange() {
         ExchangeBuilder builder = (ExchangeBuilder)((Function)TYPE_CREATOR.get(this.type)).apply(this.name);
         builder.durable(this.durable);
         if (this.autoDelete) {
            builder.autoDelete();
         }

         if (this.internal) {
            builder.internal();
         }

         if (this.delayed) {
            builder.delayed();
         }

         if (this.ignoreDeclarationExceptions) {
            builder.ignoreDeclarationExceptions();
         }

         if (!this.declare) {
            builder.suppressDeclaration();
         }

         if (ArrayUtil.isNotEmpty(this.declaringAdmins)) {
            builder.admins(this.declaringAdmins);
         }

         if (MapUtil.isNotEmpty(this.arguments)) {
            builder.withArguments(this.arguments);
         }

         return builder.build();
      }

      public String getName() {
         return this.name;
      }

      public String getType() {
         return this.type;
      }

      public boolean isDurable() {
         return this.durable;
      }

      public boolean isAutoDelete() {
         return this.autoDelete;
      }

      public boolean isInternal() {
         return this.internal;
      }

      public boolean isDelayed() {
         return this.delayed;
      }

      public boolean isIgnoreDeclarationExceptions() {
         return this.ignoreDeclarationExceptions;
      }

      public boolean isDeclare() {
         return this.declare;
      }

      public Object[] getDeclaringAdmins() {
         return this.declaringAdmins;
      }

      public Map<String, Object> getArguments() {
         return this.arguments;
      }

      public void setName(final String name) {
         this.name = name;
      }

      public void setType(final String type) {
         this.type = type;
      }

      public void setDurable(final boolean durable) {
         this.durable = durable;
      }

      public void setAutoDelete(final boolean autoDelete) {
         this.autoDelete = autoDelete;
      }

      public void setInternal(final boolean internal) {
         this.internal = internal;
      }

      public void setDelayed(final boolean delayed) {
         this.delayed = delayed;
      }

      public void setIgnoreDeclarationExceptions(final boolean ignoreDeclarationExceptions) {
         this.ignoreDeclarationExceptions = ignoreDeclarationExceptions;
      }

      public void setDeclare(final boolean declare) {
         this.declare = declare;
      }

      public void setDeclaringAdmins(final Object[] declaringAdmins) {
         this.declaringAdmins = declaringAdmins;
      }

      public void setArguments(final Map<String, Object> arguments) {
         this.arguments = arguments;
      }

      public ExchangeProperties() {
      }

      static {
         TYPE_CREATOR.put("direct", ExchangeBuilder::directExchange);
         TYPE_CREATOR.put("topic", ExchangeBuilder::topicExchange);
         TYPE_CREATOR.put("fanout", ExchangeBuilder::fanoutExchange);
         TYPE_CREATOR.put("headers", ExchangeBuilder::headersExchange);
      }
   }

   public static class BindingProperties {
      private String to;
      private String from = "amq.topic";
      private String when;
      private Binding.DestinationType type;
      private Map<String, Object> arguments;

      public BindingProperties(String from, String when, String to) {
         this.type = DestinationType.QUEUE;
         this.from = from;
         this.when = when;
         this.to = to;
      }

      public Binding buildBinding() {
         return new Binding(this.to, this.type, this.from, this.when, this.arguments);
      }

      public String getTo() {
         return this.to;
      }

      public String getFrom() {
         return this.from;
      }

      public String getWhen() {
         return this.when;
      }

      public Binding.DestinationType getType() {
         return this.type;
      }

      public Map<String, Object> getArguments() {
         return this.arguments;
      }

      public void setTo(final String to) {
         this.to = to;
      }

      public void setFrom(final String from) {
         this.from = from;
      }

      public void setWhen(final String when) {
         this.when = when;
      }

      public void setType(final Binding.DestinationType type) {
         this.type = type;
      }

      public void setArguments(final Map<String, Object> arguments) {
         this.arguments = arguments;
      }

      public BindingProperties() {
         this.type = DestinationType.QUEUE;
      }
   }
}
