package com.cameleer.server.core.rbac;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.regex.Pattern;

public class ClaimMappingService {

    private static final Logger log = LoggerFactory.getLogger(ClaimMappingService.class);

    public record MappingResult(ClaimMappingRule rule) {}

    public List<MappingResult> evaluate(List<ClaimMappingRule> rules, Map<String, Object> claims) {
        return rules.stream()
                .sorted(Comparator.comparingInt(ClaimMappingRule::priority))
                .filter(rule -> matches(rule, claims))
                .map(MappingResult::new)
                .toList();
    }

    private boolean matches(ClaimMappingRule rule, Map<String, Object> claims) {
        Object claimValue = claims.get(rule.claim());
        if (claimValue == null) return false;

        return switch (rule.matchType()) {
            case "equals" -> equalsMatch(claimValue, rule.matchValue());
            case "contains" -> containsMatch(claimValue, rule.matchValue());
            case "regex" -> regexMatch(claimValue, rule.matchValue());
            default -> {
                log.warn("Unknown match type: {}", rule.matchType());
                yield false;
            }
        };
    }

    private boolean equalsMatch(Object claimValue, String matchValue) {
        if (claimValue instanceof String s) {
            return s.equalsIgnoreCase(matchValue);
        }
        return String.valueOf(claimValue).equalsIgnoreCase(matchValue);
    }

    private boolean containsMatch(Object claimValue, String matchValue) {
        if (claimValue instanceof List<?> list) {
            return list.stream().anyMatch(item -> String.valueOf(item).equalsIgnoreCase(matchValue));
        }
        if (claimValue instanceof String s) {
            // Space-separated string (e.g., OAuth2 scope claim)
            return Arrays.stream(s.split("\\s+"))
                    .anyMatch(part -> part.equalsIgnoreCase(matchValue));
        }
        return false;
    }

    private boolean regexMatch(Object claimValue, String matchValue) {
        String s = String.valueOf(claimValue);
        try {
            return Pattern.matches(matchValue, s);
        } catch (Exception e) {
            log.warn("Invalid regex in claim mapping rule: {}", matchValue, e);
            return false;
        }
    }
}
