#!/usr/bin/env python3
"""APK SDK Analyzer CLI.  Usage: apk-analyzer [OPTIONS] <apk_file>"""
import argparse, sys, time
from pathlib import Path

# Support running directly from src/ or as frozen exe
from apk_analyzer.analyzer.apk_parser import APKParser
from apk_analyzer.analyzer.dex_parser import DEXParser
from apk_analyzer.analyzer.manifest_parser import ManifestParser
from apk_analyzer.analyzer.native_parser import NativeParser
from apk_analyzer.analyzer.version_extractor import VersionExtractor
from apk_analyzer.signature_loader import SignatureLoader
from apk_analyzer.matcher import SDKMatcher
from apk_analyzer.reporter import Reporter
from apk_analyzer.models import AnalysisResult


def _default_signatures_dir() -> Path:
    """Locate sdk_signatures bundled with the package, or fall back to repo layout."""
    # 1. Frozen exe (PyInstaller): alongside the executable
    if getattr(sys, "frozen", False):
        return Path(sys.executable).parent / "sdk_signatures"

    # 2. Installed package: sdk_signatures is inside the apk_analyzer package dir
    pkg_dir = Path(__file__).parent
    candidate = pkg_dir / "sdk_signatures"
    if candidate.exists():
        return candidate

    # 3. Dev/repo layout: two levels up from main.py (src/apk_analyzer/ -> repo root)
    repo_root = pkg_dir.parent.parent
    candidate = repo_root / "sdk_signatures"
    if candidate.exists():
        return candidate

    return pkg_dir / "sdk_signatures"  # will fail with a clear error


def main():
    p = argparse.ArgumentParser(prog="apk-analyzer",
        description="Static SDK detection for Android APK files",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="Examples:\n  apk-analyzer app.apk\n  apk-analyzer app.apk --categories push,ads")
    p.add_argument("apk_file", help="Path to APK file")
    p.add_argument("--signatures-dir", default=None)
    p.add_argument("--output-json", default=None)
    p.add_argument("--output-html", default=None)
    p.add_argument("--format", choices=["json","html","both"], default="both")
    p.add_argument("--categories", default=None, help="e.g. push,ads,social")
    p.add_argument("--verbose", "-v", action="store_true")
    p.add_argument("--version", action="version", version="apk-analyzer 1.3.0")
    args = p.parse_args()

    apk_path = Path(args.apk_file)
    if not apk_path.exists():
        print(f"[ERROR] File not found: {apk_path}", file=sys.stderr); sys.exit(1)

    sig_dir = Path(args.signatures_dir) if args.signatures_dir else _default_signatures_dir()
    if not sig_dir.exists():
        print(f"[ERROR] Signatures directory not found: {sig_dir}", file=sys.stderr)
        print(f"  Tip: use --signatures-dir <path> to specify manually", file=sys.stderr)
        sys.exit(1)

    stem = apk_path.stem
    out_json = Path(args.output_json) if args.output_json else apk_path.parent / f"{stem}_report.json"
    out_html = Path(args.output_html) if args.output_html else apk_path.parent / f"{stem}_report.html"
    categories = [c.strip() for c in args.categories.split(",")] if args.categories else None

    print(f"[*] APK SDK Analyzer v1.3.0")
    print(f"[*] Analyzing: {apk_path}")
    t0 = time.time()

    try:
        if args.verbose: print("[*] 1/5 Parsing APK...")
        apk_info = APKParser(apk_path).parse()

        if args.verbose: print(f"[*] 2/5 Parsing {apk_info.dex_count} DEX files...")
        dex_data = DEXParser(apk_info.dex_files).parse()
        apk_info.class_count = len(dex_data.class_names)

        if args.verbose: print("[*] 3/5 Parsing AndroidManifest.xml...")
        manifest = ManifestParser(apk_info.manifest_data).parse()

        if args.verbose: print("[*] 4/5 Native libs...")
        native = NativeParser(apk_info.native_libs).parse()

        if args.verbose: print("[*] 5/5 Version extraction...")
        versions = VersionExtractor(dex_data, apk_info.metainf_versions).extract()

        loader = SignatureLoader(sig_dir)
        signatures = loader.load(categories=categories)
        if args.verbose: print(f"[*] Loaded {len(signatures)} signatures from {sig_dir}")

        detected = SDKMatcher(signatures, dex_data, manifest, native, versions).match()
        duration = round(time.time() - t0, 2)

        result = AnalysisResult(apk_path=str(apk_path), apk_info=apk_info, manifest=manifest,
                                detected_sdks=detected, duration_seconds=duration,
                                signature_db_version=loader.db_version)

        tpl_path = Path(__file__).parent / "templates" / "report.html"
        if not tpl_path.exists():
            tpl_path = Path(__file__).parent.parent.parent / "templates" / "report.html"
        reporter = Reporter(result, str(tpl_path))
        if args.format in ("json","both"):
            reporter.write_json(out_json); print(f"[+] JSON: {out_json}")
        if args.format in ("html","both"):
            reporter.write_html(out_html); print(f"[+] HTML: {out_html}")

        print(f"\n{'='*52}")
        print(f"  {manifest.package_name} v{manifest.version_name}")
        print(f"  Detected: {len(detected)} SDKs  |  Time: {duration}s")
        by_cat = result.summary_by_category()
        for cat, count in sorted(by_cat.items(), key=lambda x: -x[1]):
            print(f"    {cat:<28} {count}")
        print(f"{'='*52}")

    except Exception as e:
        print(f"[ERROR] {e}", file=sys.stderr)
        if args.verbose:
            import traceback; traceback.print_exc()
        sys.exit(1)

if __name__ == "__main__":
    main()
