package com.github.rawsanj.config;

import com.github.rawsanj.messaging.RedisChatMessageListener;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicInteger;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;

import java.net.URI;

import static com.github.rawsanj.config.ChatConstants.ACTIVE_USER_KEY;
import static com.github.rawsanj.config.ChatConstants.MESSAGE_COUNTER_KEY;

@Slf4j
@Configuration(proxyBeanMethods=false)
@Profile("heroku")
public class HerokuRedisConfig {

	@Bean
	ReactiveRedisConnectionFactory reactiveRedisConnectionFactory() {
		return lettuceConnectionFactory();
	}

	@Bean
	RedisConnectionFactory redisConnectionFactory() {
		return lettuceConnectionFactory();
	}

	@SneakyThrows
	private LettuceConnectionFactory lettuceConnectionFactory() {
		String redisUrl = System.getenv("REDIS_URL");
		URI redistogoUri = new URI(redisUrl);
		RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(redistogoUri.getHost(), redistogoUri.getPort());
		redisStandaloneConfiguration.setPassword(redistogoUri.getUserInfo().split(":", 2)[1]);
		return new LettuceConnectionFactory(redisStandaloneConfiguration);
	}

	@Bean
	ReactiveStringRedisTemplate template(ReactiveRedisConnectionFactory reactiveRedisConnectionFactory) {
		return new ReactiveStringRedisTemplate(reactiveRedisConnectionFactory);
	}

	// Redis Atomic Counter to store no. of total messages sent from multiple app instances.
	@Bean
	RedisAtomicInteger chatMessageCounter(RedisConnectionFactory redisConnectionFactory) {
		return new RedisAtomicInteger(MESSAGE_COUNTER_KEY, redisConnectionFactory);
	}

	// Redis Atomic Counter to store no. of Active Users.
	@Bean
	RedisAtomicLong activeUserCounter(RedisConnectionFactory redisConnectionFactory) {
		return new RedisAtomicLong(ACTIVE_USER_KEY, redisConnectionFactory);
	}

	@Bean
	ApplicationRunner applicationRunner(RedisChatMessageListener redisChatMessageListener) {
		return args -> {
			redisChatMessageListener.subscribeMessageChannelAndPublishOnWebSocket()
				.doOnSubscribe(subscription -> log.info("Redis Listener Started"))
				.doOnError(throwable -> log.error("Error listening to Redis topic.", throwable))
				.doFinally(signalType -> log.info("Stopped Listener. Signal Type: {}", signalType))
				.subscribe();
		};
	}

}