<?php

/**
 * IconExtractor.php
 *
 * Extracts the app icon from an APK using:
 *  - resources.arsc (to resolve resource IDs)
 *  - res/mipmap-* and res/drawable-* folders
 *
 * Returns Base64 PNG thumbnails.
 */

class IconExtractor {

    private $zip;
    private $resources;

    // Preferred icon density order (highest → lowest)
    private $densityOrder = [
        "xxxhdpi",
        "xxhdpi",
        "xhdpi",
        "hdpi",
        "mdpi",
        "ldpi"
    ];

    public function __construct($zip, $resources) {
        $this->zip = $zip;
        $this->resources = $resources;
    }

    public function extractIconBase64($resourceRef) {
        // Resolve resource reference to filename
        $iconName = $this->resources->resolveIconResource($resourceRef);
        if (!$iconName) return null;

        // Remove extension if present
        $iconName = preg_replace('/\.(png|xml)$/i', '', $iconName);

        // Try to find the best density version
        foreach ($this->densityOrder as $density) {
            $paths = [
                "res/mipmap-$density/$iconName.png",
                "res/drawable-$density/$iconName.png",
                "res/mipmap-$density/$iconName.xml",
                "res/drawable-$density/$iconName.xml"
            ];

            foreach ($paths as $path) {
                $data = $this->zip->getFromName($path);
                if ($data) {
                    return $this->processIcon($data, $path);
                }
            }
        }

        // Fallback: try any drawable/mipmap
        $fallback = $this->findAnyIconVariant($iconName);
        if ($fallback) {
            return $this->processIcon($fallback['data'], $fallback['path']);
        }

        return null;
    }

    private function findAnyIconVariant($iconName) {
        for ($i = 0; $i < $this->zip->numFiles; $i++) {
            $stat = $this->zip->statIndex($i);
            $name = $stat['name'];

            if (preg_match("/$iconName\.(png|xml)$/i", $name)) {
                return [
                    "path" => $name,
                    "data" => $this->zip->getFromIndex($i)
                ];
            }
        }
        return null;
    }

    private function processIcon($data, $path) {
        // If XML vector drawable → convert to PNG
        if (str_ends_with(strtolower($path), ".xml")) {
            $png = $this->convertVectorDrawableToPNG($data);
            if ($png) {
                return base64_encode($png);
            }
        }

        // PNG: scale to thumbnail
        $img = @imagecreatefromstring($data);
        if (!$img) return null;

        $thumb = $this->scaleImage($img, 96, 96);
        ob_start();
        imagepng($thumb);
        $pngData = ob_get_clean();

        return base64_encode($pngData);
    }

    private function scaleImage($img, $maxW, $maxH) {
        $w = imagesx($img);
        $h = imagesy($img);

        $scale = min($maxW / $w, $maxH / $h);
        $newW = max(1, intval($w * $scale));
        $newH = max(1, intval($h * $scale));

        $thumb = imagecreatetruecolor($newW, $newH);
        imagealphablending($thumb, false);
        imagesavealpha($thumb, true);

        imagecopyresampled($thumb, $img, 0, 0, 0, 0, $newW, $newH, $w, $h);

        return $thumb;
    }

    private function convertVectorDrawableToPNG($xmlData) {
        // Vector drawable conversion is non-trivial.
        // For now, return null so PNG fallback is used.
        return null;
    }
}