<?php
namespace PortalPeople\filediff;

class FileDiffService
{
    /**
     * Compare uploaded zip/hash file against local files
     * @param string $uploadedFilePath
     * @return array
     */
    public function compareUploaded(string $uploadedFilePath): array
    {
        // Example: Assume uploaded file is a zip containing core files
        $tempDir = sys_get_temp_dir() . '/filediff_' . uniqid();
        mkdir($tempDir);
        $zip = new \ZipArchive();
        $zip->open($uploadedFilePath);
        $zip->extractTo($tempDir);
        $zip->close();

        $remoteHashes = $this->generateHashes($tempDir);
        $localHashes = $this->generateHashes(Yii::getAlias('@app'));

        $diff = $this->compareHashes($localHashes, $remoteHashes);
        $this->cleanup($tempDir);
        return $diff;
    }

    /**
     * Generate hashes for all files in a directory
     */
    public function generateHashes(string $dir): array
    {
        $hashes = [];
        $rii = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir));
        foreach ($rii as $file) {
            if ($file->isDir()) continue;
            $relPath = str_replace($dir . '/', '', $file->getPathname());
            $hashes[$relPath] = hash_file('sha256', $file->getPathname());
        }
        return $hashes;
    }

    /**
     * Compare two hash lists
     */
    public function compareHashes(array $local, array $remote): array
    {
        $added = array_diff_key($remote, $local);
        $removed = array_diff_key($local, $remote);
        $changed = [];
        foreach ($local as $file => $hash) {
            if (isset($remote[$file]) && $remote[$file] !== $hash) {
                $changed[$file] = [
                    'local' => $hash,
                    'remote' => $remote[$file],
                ];
            }
        }
        return [
            'added' => $added,
            'removed' => $removed,
            'changed' => $changed,
        ];
    }

    /**
     * Cleanup temp directory
     */
    public function cleanup(string $dir): void
    {
        $files = new \RecursiveIteratorIterator(
            new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS),
            \RecursiveIteratorIterator::CHILD_FIRST
        );
        foreach ($files as $file) {
            $file->isDir() ? rmdir($file->getPathname()) : unlink($file->getPathname());
        }
        rmdir($dir);
    }
}
