"""Data models for APK SDK Analyzer."""
from dataclasses import dataclass, field
from typing import Dict, List, Optional
from datetime import datetime, timezone


@dataclass
class APKInfo:
    package_name: str = ""
    app_name: str = ""
    version_name: str = ""
    version_code: int = 0
    min_sdk: int = 0
    target_sdk: int = 0
    dex_files: List[bytes] = field(default_factory=list)
    dex_count: int = 0
    class_count: int = 0
    native_libs: List[str] = field(default_factory=list)
    native_lib_arches: Dict[str, List[str]] = field(default_factory=dict)
    native_lib_descriptions: Dict[str, str] = field(default_factory=dict)
    permissions: List[str] = field(default_factory=list)
    manifest_data: bytes = b""
    resources_arsc: bytes = b""
    metainf_versions: Dict[str, str] = field(default_factory=dict)
    signature_sha256: str = ""
    signing_schemes: List[str] = field(default_factory=list)
    signing_certificates: List[Dict[str, str]] = field(default_factory=list)
    signing_organization: str = ""
    source_channel: str = "unknown"
    source_channel_confidence: str = "low"
    source_channel_evidence: List[str] = field(default_factory=list)
    source_channel_raw: str = ""
    channel_hints: List[str] = field(default_factory=list)
    file_size_bytes: int = 0
    native_abis: List[str] = field(default_factory=list)
    abi_support: str = "unknown"
    resource_dirs: Dict[str, List[str]] = field(default_factory=dict)  # resource_name -> [dpi1, dpi2, ...]
    resource_dpis: List[str] = field(default_factory=list)  # All detected DPI qualifiers
    dpi_support: str = "unknown"
    resource_references: set[str] = field(default_factory=set)  # Set of referenced resource names


@dataclass
class DEXData:
    string_pool: List[str] = field(default_factory=list)
    class_names: List[str] = field(default_factory=list)
    buildconfig_versions: Dict[str, str] = field(default_factory=dict)
    _package_prefix_set: set = field(default_factory=set, repr=False)

    def build_index(self):
        self._package_prefix_set = set()
        for cls in self.class_names:
            parts = cls.split(".")
            for i in range(1, len(parts) + 1):
                self._package_prefix_set.add(".".join(parts[:i]))
            self._package_prefix_set.add(cls.split("$")[0])

    def has_package(self, prefix: str) -> bool:
        if self._package_prefix_set:
            return prefix in self._package_prefix_set
        return any(c == prefix or c.startswith(prefix + ".") for c in self.class_names)


@dataclass
class ManifestData:
    package_name: str = ""
    version_name: str = ""
    version_code: int = 0
    min_sdk: int = 0
    target_sdk: int = 0
    app_name: str = ""
    app_label_ref: str = ""
    permissions: List[str] = field(default_factory=list)
    activities: List[str] = field(default_factory=list)
    services: List[str] = field(default_factory=list)
    receivers: List[str] = field(default_factory=list)
    providers: List[str] = field(default_factory=list)
    intent_actions: List[str] = field(default_factory=list)
    meta_data: Dict[str, str] = field(default_factory=dict)


@dataclass
class NativeData:
    lib_names: List[str] = field(default_factory=list)
    abis: List[str] = field(default_factory=list)


@dataclass
class ResourceAdvice:
    """Advice for a single resource."""
    resource_name: str
    resource_type: str
    current_dpis: List[str]
    issues: List[str] = field(default_factory=list)
    recommendations: List[str] = field(default_factory=list)
    priority: str = "low"
    can_remove: bool = False
    should_add: List[str] = field(default_factory=list)
    
    def to_dict(self) -> dict:
        return {
            "resource_name": self.resource_name,
            "resource_type": self.resource_type,
            "current_dpis": self.current_dpis,
            "issues": self.issues,
            "recommendations": self.recommendations,
            "priority": self.priority,
            "can_remove": self.can_remove,
            "should_add": self.should_add,
        }


@dataclass
class ResourceData:
    """Resource DPI support information."""
    resource_dirs: Dict[str, List[str]] = field(default_factory=dict)  # resource_name -> [dpi1, dpi2, ...]
    all_dpis: List[str] = field(default_factory=list)  # All detected DPI qualifiers
    dpi_support: str = "unknown"  # Summary like "mdpi/xhdpi/xxhdpi" or "All common DPIs"
    resource_references: set[str] = field(default_factory=set)  # Set of referenced resource names
    advice: List[ResourceAdvice] = field(default_factory=list)  # Best practice advice
    summary_recommendations: List[str] = field(default_factory=list)  # High-level recommendations


@dataclass
class DetectionEvidence:
    matched_packages: List[str] = field(default_factory=list)
    matched_natives: List[str] = field(default_factory=list)
    matched_manifest_services: List[str] = field(default_factory=list)
    matched_manifest_receivers: List[str] = field(default_factory=list)
    matched_string_patterns: List[str] = field(default_factory=list)


@dataclass
class SDKRisk:
    permissions: List[str] = field(default_factory=list)
    data_collection: List[str] = field(default_factory=list)
    privacy_risk: str = "unknown"
    notes: str = ""


@dataclass
class DetectedSDK:
    id: str = ""
    name: str = ""
    category: str = ""
    vendor: str = ""
    description: str = ""
    detected: bool = True
    confidence: str = "high"
    version: Optional[str] = None
    version_source: Optional[str] = None
    detection_evidence: DetectionEvidence = field(default_factory=DetectionEvidence)
    risk: SDKRisk = field(default_factory=SDKRisk)

    def to_dict(self) -> dict:
        return {
            "id": self.id, "name": self.name, "category": self.category,
            "vendor": self.vendor, "description": self.description,
            "detected": self.detected, "confidence": self.confidence,
            "version": self.version, "version_source": self.version_source,
            "detection_evidence": {
                "matched_packages": self.detection_evidence.matched_packages,
                "matched_natives": self.detection_evidence.matched_natives,
                "matched_manifest_services": self.detection_evidence.matched_manifest_services,
                "matched_manifest_receivers": self.detection_evidence.matched_manifest_receivers,
                "matched_string_patterns": self.detection_evidence.matched_string_patterns,
            },
            "risk": {
                "permissions": self.risk.permissions,
                "data_collection": self.risk.data_collection,
                "privacy_risk": self.risk.privacy_risk,
                "notes": self.risk.notes,
            },
        }


@dataclass
class AnalysisResult:
    apk_path: str = ""
    apk_info: APKInfo = field(default_factory=APKInfo)
    manifest: ManifestData = field(default_factory=ManifestData)
    detected_sdks: List[DetectedSDK] = field(default_factory=list)
    resource_data: ResourceData = field(default_factory=ResourceData)
    duration_seconds: float = 0.0
    signature_db_version: str = "unknown"
    TOOL_VERSION: str = field(default="1.0.0", init=False, repr=False)

    def summary_by_category(self) -> Dict[str, int]:
        counts: Dict[str, int] = {}
        for sdk in self.detected_sdks:
            counts[sdk.category] = counts.get(sdk.category, 0) + 1
        return counts

    def to_dict(self) -> dict:
        info = self.apk_info
        manifest = self.manifest
        return {
            "meta": {
                "tool_version": "1.0.0",
                "signature_db_version": self.signature_db_version,
                "analysis_time": datetime.now(timezone.utc).isoformat(),
                "apk_path": self.apk_path,
                "analysis_duration_seconds": self.duration_seconds,
            },
            "apk_info": {
                "package_name": info.package_name or manifest.package_name,
                "app_name": info.app_name or manifest.app_name,
                "version_name": info.version_name or manifest.version_name,
                "version_code": info.version_code or manifest.version_code,
                "min_sdk": info.min_sdk or manifest.min_sdk,
                "target_sdk": info.target_sdk or manifest.target_sdk,
                "dex_count": info.dex_count,
                "class_count": info.class_count,
                "native_libs": info.native_libs,
                "native_lib_arches": info.native_lib_arches,
                "native_lib_descriptions": info.native_lib_descriptions,
                "permissions": manifest.permissions,
                "signature_sha256": info.signature_sha256,
                "signing_schemes": info.signing_schemes,
                "signing_certificates": info.signing_certificates,
                "signing_organization": info.signing_organization,
                "source_channel": info.source_channel,
                "source_channel_confidence": info.source_channel_confidence,
                "source_channel_evidence": info.source_channel_evidence,
                "source_channel_raw": info.source_channel_raw,
                "channel_hints": info.channel_hints,
                "file_size_bytes": info.file_size_bytes,
                "abi_support": info.abi_support,
                "native_abis": info.native_abis,
                "resource_dirs": info.resource_dirs,
                "resource_dpis": info.resource_dpis,
                "dpi_support": info.dpi_support,
                "resource_references": list(info.resource_references),
            },
            "detected_sdks": [sdk.to_dict() for sdk in self.detected_sdks],
            "resource_data": {
                "resource_dirs": self.resource_data.resource_dirs,
                "all_dpis": self.resource_data.all_dpis,
                "dpi_support": self.resource_data.dpi_support,
                "resource_references": list(self.resource_data.resource_references),
                "advice": [a.to_dict() for a in self.resource_data.advice],
                "summary_recommendations": self.resource_data.summary_recommendations,
            },
            "summary": {
                "total_detected": len(self.detected_sdks),
                "by_category": self.summary_by_category(),
                "high_risk_count": sum(1 for s in self.detected_sdks if s.risk.privacy_risk == "high"),
                "medium_risk_count": sum(1 for s in self.detected_sdks if s.risk.privacy_risk == "medium"),
                "versions_extracted": sum(1 for s in self.detected_sdks if s.version),
            },
        }
