package party.cybsec.griefdetect.core;

import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import party.cybsec.griefdetect.GriefDetectPlugin;
import party.cybsec.griefdetect.config.PluginConfig;

import java.util.List;
import java.util.stream.Collectors;

/**
 * Confidence engine for calculating grief detection confidence scores.
 * Implements the confidence system with base factors and player proximity modifiers.
 */
public class ConfidenceEngine {
    
    private final GriefDetectPlugin plugin;
    private final PluginConfig config;
    
    // Configuration constants from config
    private static final double PLAYER_PROXIMITY_RADIUS = 50.0;
    private static final double NO_PLAYERS_MULTIPLIER = 0.5; // Reduce confidence when no players nearby
    
    public ConfidenceEngine(GriefDetectPlugin plugin) {
        this.plugin = plugin;
        this.config = plugin.getPluginConfig();
    }
    
    /**
     * Calculate confidence score for a detection event.
     * 
     * @param detectionType Type of detection
     * @param world The world where detection occurred
     * @param center Center location of the cluster
     * @param minX, minY, minZ Minimum bounding box coordinates
     * @param maxX, maxY, maxZ Maximum bounding box coordinates
     * @param blockCount Total number of blocks in the cluster
     * @param duration Duration of the event in milliseconds
     * @return Confidence score between 0.0 and 100.0
     */
    public double calculateConfidence(String detectionType, World world, Location center,
                                    int minX, int minY, int minZ,
                                    int maxX, int maxY, int maxZ,
                                    int blockCount, long duration) {
        
        double confidence = 0.0;
        
        // Base factors
        confidence += calculateVolumeFactor(blockCount);
        confidence += calculateGrowthSpeedFactor(blockCount, duration);
        confidence += calculateExpansionRadiusFactor(center, minX, minY, minZ, maxX, maxY, maxZ);
        confidence += calculateDurationFactor(duration);
        confidence += calculateVerticalSpanFactor(minY, maxY);
        confidence += calculateIrregularityFactor(minX, minY, minZ, maxX, maxY, maxZ, blockCount);
        
        // Apply player proximity modifier
        confidence = applyPlayerProximityModifier(confidence, world, center);
        
        // Clamp to 0-100 range
        return Math.max(0.0, Math.min(100.0, confidence));
    }
    
    /**
     * Calculate volume factor based on total block count.
     */
    private double calculateVolumeFactor(int blockCount) {
        if (blockCount < 100) return 10.0;
        if (blockCount < 500) return 25.0;
        if (blockCount < 1000) return 40.0;
        if (blockCount < 2000) return 60.0;
        return 80.0;
    }
    
    /**
     * Calculate growth speed factor based on blocks per second.
     */
    private double calculateGrowthSpeedFactor(int blockCount, long duration) {
        if (duration <= 0) return 0.0;
        
        double blocksPerSecond = (double) blockCount / (duration / 1000.0);
        
        if (blocksPerSecond < 1) return 5.0;
        if (blocksPerSecond < 5) return 15.0;
        if (blocksPerSecond < 10) return 25.0;
        if (blocksPerSecond < 20) return 40.0;
        return 60.0;
    }
    
    /**
     * Calculate expansion radius factor.
     */
    private double calculateExpansionRadiusFactor(Location center, int minX, int minY, int minZ, int maxX, int maxY, int maxZ) {
        double radius = calculateExpansionRadius(center, minX, minY, minZ, maxX, maxY, maxZ);
        
        if (radius < 10) return 5.0;
        if (radius < 25) return 15.0;
        if (radius < 50) return 30.0;
        if (radius < 100) return 50.0;
        return 70.0;
    }
    
    /**
     * Calculate duration factor.
     */
    private double calculateDurationFactor(long duration) {
        double seconds = duration / 1000.0;
        
        if (seconds < 10) return 5.0;
        if (seconds < 30) return 15.0;
        if (seconds < 60) return 25.0;
        if (seconds < 120) return 40.0;
        return 60.0;
    }
    
    /**
     * Calculate vertical span factor.
     */
    private double calculateVerticalSpanFactor(int minY, int maxY) {
        int verticalSpan = maxY - minY + 1;
        
        if (verticalSpan < 3) return 5.0;
        if (verticalSpan < 10) return 15.0;
        if (verticalSpan < 25) return 30.0;
        return 50.0;
    }
    
    /**
     * Calculate irregularity factor based on bounding box efficiency.
     */
    private double calculateIrregularityFactor(int minX, int minY, int minZ, int maxX, int maxY, int maxZ, int blockCount) {
        int volume = (maxX - minX + 1) * (maxY - minY + 1) * (maxZ - minZ + 1);
        if (volume == 0) return 0.0;
        
        double efficiency = (double) blockCount / volume;
        
        // Lower efficiency (more irregular) increases confidence
        if (efficiency > 0.8) return 5.0;  // Very regular shape
        if (efficiency > 0.5) return 15.0;
        if (efficiency > 0.3) return 30.0;
        if (efficiency > 0.1) return 50.0;
        return 70.0;  // Very irregular
    }
    
    /**
     * Apply player proximity modifier to confidence.
     */
    private double applyPlayerProximityModifier(double baseConfidence, World world, Location center) {
        List<Player> nearbyPlayers = world.getPlayers().stream()
            .filter(player -> player.getLocation().distance(center) <= PLAYER_PROXIMITY_RADIUS)
            .collect(Collectors.toList());
        
        if (nearbyPlayers.isEmpty()) {
            // No players nearby - reduce confidence
            return baseConfidence * NO_PLAYERS_MULTIPLIER;
        }
        
        // Players nearby - full confidence
        return baseConfidence;
    }
    
    /**
     * Calculate expansion radius helper method.
     */
    private double calculateExpansionRadius(Location center, int minX, int minY, int minZ, int maxX, int maxY, int maxZ) {
        double dx = Math.max(Math.abs(center.getBlockX() - minX), Math.abs(center.getBlockX() - maxX));
        double dy = Math.max(Math.abs(center.getBlockY() - minY), Math.abs(center.getBlockY() - maxY));
        double dz = Math.max(Math.abs(center.getBlockZ() - minZ), Math.abs(center.getBlockZ() - maxZ));
        return Math.sqrt(dx * dx + dy * dy + dz * dz);
    }
    
    /**
     * Check if confidence meets ignore threshold.
     */
    public boolean shouldIgnore(double confidence) {
        return confidence < config.getIgnoreThreshold();
    }
    
    /**
     * Check if confidence meets chat alert threshold.
     */
    public boolean shouldAlertChat(double confidence) {
        return confidence >= config.getChatAlertThreshold();
    }
    
    /**
     * Check if confidence meets webhook threshold.
     */
    public boolean shouldWebhook(double confidence) {
        return confidence >= config.getWebhookThreshold();
    }
}