/**
 * @file UserResidenceDatabase.java
 * @brief Management of user residence data via Redis.
 */

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.io.InputStream;
import java.util.Scanner;

/**
 * @class UserResidenceDatabase
 * @brief High-performance database wrapper for user residence lookups using Redis.
 *
 * This class interacts with a Redis instance to store and retrieve the home 
 * country of bank users. It is a critical component of the fraud detection 
 * system, allowing the Banking API to quickly compare transaction locations 
 * against a user's verified residence.
 */
public class UserResidenceDatabase {
    
    /** @brief The hostname of the Redis server. */
    private static final String REDIS_HOST = "localhost";
    
    /** @brief The network port on which the Redis server is listening. */
    private static final int REDIS_PORT = 6379;
    
    /** @brief The text file used to populate Redis with initial data. */
    private static final String USER_RESIDENCE_FILE = "user-residence.txt";
    
    /** 
     * @brief A pool of Redis connections.
     * @details Using a JedisPool is thread-safe and more efficient than opening 
     * a new connection for every request.
     */
    private final JedisPool jedisPool;

    /**
     * @brief Constructor for UserResidenceDatabase.
     * 
     * Initializes the Redis connection pool and triggers the automatic 
     * seeding of data from the local @ref USER_RESIDENCE_FILE.
     */
    public UserResidenceDatabase() {
        this.jedisPool = new JedisPool(REDIS_HOST, REDIS_PORT);
        seedRedisFromFile();
    }

    /**
     * @brief Fetches a user's home country from the Redis database.
     * 
     * This method performs an O(1) lookup in Redis.
     * 
     * @param user The username or ID of the customer.
     * @return String The country string representing the user's residence.
     * @throws RuntimeException if the user key does not exist in Redis.
     */
    public String getUserResidence(String user) {
        try (Jedis jedis = jedisPool.getResource()) {
            String residence = jedis.get(user);
            
            /** @note Absence of a user in the DB is treated as a critical data error. */
            if (residence == null) {
                throw new RuntimeException("User " + user + " doesn't exist in Redis database");
            }
            return residence;
        }
    }

    /**
     * @brief Populates the Redis instance with data from the local resource file.
     * 
     * Reads the @c user-residence.txt file and performs a @c SET operation in 
     * Redis for every "User Location" pair found.
     * 
     * @details This allows the system to be "reset" or initialized with known 
     * user data during the startup phase of the Banking API.
     */
    private void seedRedisFromFile() {
        try (Jedis jedis = jedisPool.getResource()) {
            InputStream inputStream = getClass().getClassLoader().getResourceAsStream(USER_RESIDENCE_FILE);
            
            if (inputStream == null) {
                System.err.println("Seeding failed: " + USER_RESIDENCE_FILE + " not found.");
                return;
            }

            Scanner scanner = new Scanner(inputStream);
            while (scanner.hasNextLine()) {
                String line = scanner.nextLine();
                String[] userResidencePair = line.split(" ");
                
                if (userResidencePair.length >= 2) {
                    // Store in Redis: Key = Username, Value = Country
                    jedis.set(userResidencePair[0], userResidencePair[1]);
                }
            }
            
            System.out.println("Redis database seeded successfully from file.");
            scanner.close();
        }
    }
}