GeographicAnomalyRule.java

package com.hsbc.fraud.rules.impl;

import com.hsbc.fraud.model.AlertType;
import com.hsbc.fraud.model.Transaction;
import com.hsbc.fraud.rules.FraudRule;
import com.hsbc.fraud.rules.RuleResult;

import java.util.HashSet;
import java.util.Optional;
import java.util.Set;

/**
 * Rule to detect transactions from high-risk geographic locations.
 * Flags transactions originating from countries with high fraud rates.
 */
public class GeographicAnomalyRule implements FraudRule {

    private static final long serialVersionUID = 1L;

    private final Set<String> highRiskCountries;
    private final Set<String> blockedCountries;

    public GeographicAnomalyRule() {
        this.highRiskCountries = new HashSet<>();
        this.blockedCountries = new HashSet<>();
        initializeDefaultLists();
    }

    public GeographicAnomalyRule(Set<String> highRiskCountries, Set<String> blockedCountries) {
        this.highRiskCountries = new HashSet<>(highRiskCountries);
        this.blockedCountries = new HashSet<>(blockedCountries);
    }

    private void initializeDefaultLists() {
        // Sample high-risk countries (for demonstration only)
        highRiskCountries.add("XX"); // Fictional country code
        highRiskCountries.add("YY");
        
        // Sample blocked countries
        blockedCountries.add("ZZ"); // Fictional blocked country
    }

    @Override
    public String getRuleName() {
        return "GEOGRAPHIC_ANOMALY";
    }

    @Override
    public String getDescription() {
        return "Detects transactions from high-risk or blocked geographic locations";
    }

    @Override
    public Optional<RuleResult> evaluate(Transaction transaction) {
        if (transaction == null || transaction.getCountryCode() == null) {
            return Optional.empty();
        }

        String countryCode = transaction.getCountryCode().toUpperCase();

        // Check blocked countries first
        if (blockedCountries.contains(countryCode)) {
            return Optional.of(new RuleResult(
                    getRuleName(),
                    AlertType.GEOGRAPHIC_ANOMALY,
                    0.98,
                    String.format("Transaction from BLOCKED country: %s", countryCode)
            ));
        }

        // Check high-risk countries
        if (highRiskCountries.contains(countryCode)) {
            return Optional.of(new RuleResult(
                    getRuleName(),
                    AlertType.GEOGRAPHIC_ANOMALY,
                    0.6,
                    String.format("Transaction from HIGH-RISK country: %s", countryCode)
            ));
        }

        return Optional.empty();
    }

    @Override
    public int getPriority() {
        return 80;
    }

    public void addHighRiskCountry(String countryCode) {
        highRiskCountries.add(countryCode.toUpperCase());
    }

    public void addBlockedCountry(String countryCode) {
        blockedCountries.add(countryCode.toUpperCase());
    }

    public boolean isHighRisk(String countryCode) {
        return countryCode != null && highRiskCountries.contains(countryCode.toUpperCase());
    }

    public boolean isBlocked(String countryCode) {
        return countryCode != null && blockedCountries.contains(countryCode.toUpperCase());
    }
}