"""Resource DPI Advisor - provides best practice recommendations for Android resources."""
from typing import Dict, List, Tuple
from dataclasses import dataclass, field


# Standard DPI qualifiers in order of density
_DPI_ORDER = ["ldpi", "mdpi", "hdpi", "tvdpi", "xhdpi", "xxhdpi", "xxxhdpi", "nodpi", "anydpi"]

# DPI density values (dpi)
_DPI_VALUES = {
    "ldpi": 120,
    "mdpi": 160,
    "hdpi": 240,
    "tvdpi": 213,
    "xhdpi": 320,
    "xxhdpi": 480,
    "xxxhdpi": 640,
    "nodpi": 0,  # No scaling
    "anydpi": 0,  # Vector drawables
}

# Essential DPI set for most resources
_ESSENTIAL_DPIS = {"mdpi", "hdpi", "xhdpi", "xxhdpi"}

# Recommended DPI set for app icons (mipmap)
_ICON_DPIS = {"mdpi", "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"}

# Minimum DPI set (at least one of these)
_MINIMUM_DPIS = {"mdpi", "hdpi", "xhdpi"}


@dataclass
class ResourceAdvice:
    """Advice for a single resource."""
    resource_name: str
    resource_type: str  # "drawable" or "mipmap"
    current_dpis: List[str]
    issues: List[str] = field(default_factory=list)
    recommendations: List[str] = field(default_factory=list)
    priority: str = "low"  # "high", "medium", "low"
    can_remove: bool = False
    should_add: List[str] = field(default_factory=list)


@dataclass
class ResourceAnalysis:
    """Overall resource DPI analysis."""
    total_resources: int
    resources_with_issues: int
    resources_optimal: int
    total_advice: List[ResourceAdvice] = field(default_factory=list)
    summary_recommendations: List[str] = field(default_factory=list)


def _is_icon_resource(resource_name: str) -> bool:
    """Check if resource is an icon (mipmap or common icon names)."""
    if resource_name.startswith("mipmap/"):
        return True
    icon_names = {"icon", "ic_launcher", "ic_app", "app_icon", "logo"}
    return any(name in resource_name.lower() for name in icon_names)


def _analyze_resource_dpi_coverage(resource_name: str, dpis: List[str]) -> Tuple[List[str], List[str]]:
    """
    Analyze DPI coverage and return (issues, recommendations).
    
    Issues:
    - Missing essential DPIs
    - Only low DPI provided (will be upscaled, causing blur)
    - Only high DPI provided (waste of space on low-end devices)
    - Inconsistent DPI coverage
    - Unnecessary DPI combinations
    
    Recommendations:
    - Which DPIs to add
    - Which DPIs can be removed
    - Whether to use nodpi
    """
    issues = []
    recommendations = []
    
    is_icon = _is_icon_resource(resource_name)
    resource_type = "mipmap" if resource_name.startswith("mipmap/") else "drawable"
    dpi_set = set(dpis)
    
    # Check for nodpi/anydpi
    has_nodpi = "nodpi" in dpi_set or "anydpi" in dpi_set
    if has_nodpi:
        if len(dpi_set) > 1:
            issues.append("Has nodpi/anydpi but also provides DPI-specific versions (redundant)")
            recommendations.append("Consider removing DPI-specific versions if nodpi version is sufficient")
        else:
            recommendations.append("Using nodpi is fine for non-scalable resources (like backgrounds)")
        return issues, recommendations
    
    # Determine expected DPI set
    if is_icon:
        expected_dpis = _ICON_DPIS
        min_dpis = {"mdpi", "hdpi", "xhdpi", "xxhdpi"}
    else:
        expected_dpis = _ESSENTIAL_DPIS
        min_dpis = {"mdpi", "hdpi", "xhdpi"}
    
    # Check if has minimum coverage
    has_minimum = bool(dpi_set & min_dpis)
    if not has_minimum:
        issues.append(f"Missing minimum DPI coverage (should have at least one of: {', '.join(min_dpis)})")
        recommendations.append(f"Add at least one of: {', '.join(min_dpis)}")
    
    # Check for essential DPIs
    missing_essential = expected_dpis - dpi_set
    if missing_essential:
        if is_icon:
            issues.append(f"Missing recommended DPIs for icons: {', '.join(sorted(missing_essential))}")
        else:
            issues.append(f"Missing essential DPIs: {', '.join(sorted(missing_essential))}")
        
        # Prioritize recommendations
        high_priority = missing_essential & {"xhdpi", "xxhdpi"}
        if high_priority:
            recommendations.append(f"High priority: Add {', '.join(sorted(high_priority))} (most common modern devices)")
        medium_priority = missing_essential & {"hdpi", "mdpi"}
        if medium_priority:
            recommendations.append(f"Medium priority: Add {', '.join(sorted(medium_priority))} (older devices)")
    
    # Check for only low DPI (will be upscaled)
    only_low = dpi_set <= {"ldpi", "mdpi"}
    if only_low and len(dpi_set) > 0:
        issues.append("Only provides low DPI versions (will be upscaled on modern devices, may appear blurry)")
        recommendations.append("Add hdpi, xhdpi, or xxhdpi versions for better quality on modern devices")
    
    # Check for only high DPI (waste of space)
    only_high = dpi_set >= {"xxhdpi", "xxxhdpi"} and not (dpi_set & {"mdpi", "hdpi", "xhdpi"})
    if only_high:
        issues.append("Only provides high DPI versions (waste of space on low-end devices)")
        recommendations.append("Consider adding mdpi or hdpi version for better compatibility")
    
    # Check for gaps in DPI sequence
    if len(dpi_set) > 1:
        dpi_values = [_DPI_VALUES.get(d, 0) for d in dpis if d in _DPI_VALUES]
        if len(dpi_values) > 1:
            # Check for large gaps (more than 2x jump)
            for i in range(len(dpi_values) - 1):
                if dpi_values[i] > 0 and dpi_values[i+1] > 0:
                    ratio = dpi_values[i+1] / dpi_values[i]
                    if ratio > 2.5:
                        issues.append(f"Large DPI gap between {dpis[i]} and {dpis[i+1]} (may cause scaling issues)")
                        recommendations.append(f"Consider adding intermediate DPI between {dpis[i]} and {dpis[i+1]}")
    
    # Check for unnecessary ldpi (rarely needed in modern apps)
    if "ldpi" in dpi_set and len(dpi_set) == 1:
        issues.append("Only provides ldpi (very old devices, rarely needed)")
        recommendations.append("Consider removing ldpi or adding mdpi/hdpi for better compatibility")
    elif "ldpi" in dpi_set and not (dpi_set & {"mdpi", "hdpi"}):
        issues.append("Has ldpi but missing mdpi/hdpi (inconsistent coverage)")
        recommendations.append("Add mdpi or hdpi for better device coverage")
    
    # Check for tvdpi (TV-specific, usually not needed)
    if "tvdpi" in dpi_set and len(dpi_set) == 1:
        issues.append("Only provides tvdpi (TV-specific, usually not needed for phones)")
        recommendations.append("Consider adding mdpi/hdpi for phone compatibility")
    
    return issues, recommendations


def analyze_resources(resource_dirs: Dict[str, List[str]], 
                     resource_references: set[str]) -> ResourceAnalysis:
    """
    Analyze all resources and provide recommendations.
    
    Args:
        resource_dirs: Dict mapping resource_name -> [dpi1, dpi2, ...]
        resource_references: Set of referenced resource names
    
    Returns:
        ResourceAnalysis with advice for each resource
    """
    all_advice = []
    
    for resource_name, dpis in resource_dirs.items():
        resource_type = "mipmap" if resource_name.startswith("mipmap/") else "drawable"
        is_referenced = resource_name.split("/")[-1] in resource_references or \
                       any(r in resource_name for r in resource_references)
        
        issues, recommendations = _analyze_resource_dpi_coverage(resource_name, dpis)
        
        # Determine priority
        priority = "low"
        if issues:
            if any("Missing essential" in i or "Missing recommended" in i for i in issues):
                priority = "high"
            elif any("Only provides" in i for i in issues):
                priority = "medium"
        
        # Check if resource can be removed (unused and has issues)
        can_remove = not is_referenced and (len(dpis) == 1 and "ldpi" in dpis or len(issues) > 2)
        
        # Determine which DPIs should be added
        should_add = []
        is_icon = _is_icon_resource(resource_name)
        if is_icon:
            expected = _ICON_DPIS
        else:
            expected = _ESSENTIAL_DPIS
        
        missing = expected - set(dpis)
        if missing and is_referenced:
            # Prioritize: xxhdpi, xhdpi > hdpi, mdpi > others
            priority_order = ["xxhdpi", "xhdpi", "xxxhdpi", "hdpi", "mdpi"]
            should_add = [d for d in priority_order if d in missing][:3]  # Top 3 missing
        
        advice = ResourceAdvice(
            resource_name=resource_name,
            resource_type=resource_type,
            current_dpis=dpis,
            issues=issues,
            recommendations=recommendations,
            priority=priority,
            can_remove=can_remove,
            should_add=should_add,
        )
        all_advice.append(advice)
    
    # Generate summary recommendations
    summary = _generate_summary_recommendations(all_advice, resource_references)
    
    resources_with_issues = sum(1 for a in all_advice if a.issues)
    resources_optimal = sum(1 for a in all_advice if not a.issues and a.current_dpis)
    
    return ResourceAnalysis(
        total_resources=len(all_advice),
        resources_with_issues=resources_with_issues,
        resources_optimal=resources_optimal,
        total_advice=all_advice,
        summary_recommendations=summary,
    )


def _generate_summary_recommendations(advice_list: List[ResourceAdvice], 
                                     resource_references: set[str]) -> List[str]:
    """Generate high-level summary recommendations."""
    recommendations = []
    
    # Count resources by type
    icons = [a for a in advice_list if _is_icon_resource(a.resource_name)]
    drawables = [a for a in advice_list if not _is_icon_resource(a.resource_name)]
    
    # Check for unused resources
    unused = [a for a in advice_list if a.can_remove]
    if unused:
        recommendations.append(f"Found {len(unused)} unused or problematic resources that can be removed to reduce APK size")
    
    # Check icon coverage
    icons_with_issues = [a for a in icons if a.issues]
    if icons_with_issues:
        recommendations.append(f"{len(icons_with_issues)} icon(s) need better DPI coverage (icons should have mdpi, hdpi, xhdpi, xxhdpi, xxxhdpi)")
    
    # Check drawable coverage
    drawables_with_issues = [a for a in drawables if a.issues]
    if drawables_with_issues:
        recommendations.append(f"{len(drawables_with_issues)} drawable(s) need better DPI coverage (recommended: mdpi, hdpi, xhdpi, xxhdpi)")
    
    # Check for resources that only have low DPI
    only_low = [a for a in advice_list if set(a.current_dpis) <= {"ldpi", "mdpi"} and a.current_dpis]
    if only_low:
        recommendations.append(f"{len(only_low)} resource(s) only have low DPI versions (will be upscaled, may appear blurry on modern devices)")
    
    # Check for resources that only have high DPI
    only_high = [a for a in advice_list if set(a.current_dpis) >= {"xxhdpi", "xxxhdpi"} and 
                 not (set(a.current_dpis) & {"mdpi", "hdpi", "xhdpi"})]
    if only_high:
        recommendations.append(f"{len(only_high)} resource(s) only have high DPI versions (waste of space on low-end devices)")
    
    # General best practices
    if not recommendations:
        recommendations.append("Resource DPI coverage looks good! All resources have appropriate DPI versions.")
    else:
        recommendations.append("Best practice: Provide mdpi, hdpi, xhdpi, xxhdpi for most resources. Icons should also include xxxhdpi.")
        recommendations.append("Note: Android will scale resources automatically, but providing appropriate DPIs ensures best quality.")
    
    return recommendations
