<?php
class ChecksumManager {
    private $manifest_file;
    private $packages_dir;
    private $manifest_data;
    
    public function __construct($base_path = null) {
        if ($base_path === null) {
            $base_path = dirname(__FILE__);
        }
        
        $this->manifest_file = $base_path . '/manifest.json';
        $this->packages_dir = $base_path . '/packages/';
        $this->loadManifest();
    }
    
    private function loadManifest() {
        if (file_exists($this->manifest_file)) {
            $this->manifest_data = json_decode(file_get_contents($this->manifest_file), true);
        } else {
            $this->manifest_data = [
                'latest_version' => '',
                'packages' => []
            ];
        }
    }
    
    public function addPackage($version, $package_file, $min_version = null) {
        if (!file_exists($package_file)) {
            throw new Exception("Package file not found: $package_file");
        }
        
        // Generate checksum
        $checksum = md5_file($package_file);
        
        // Add to manifest
        $this->manifest_data['packages'][$version] = [
            'url' => '/packages/' . basename($package_file),
            'checksum' => $checksum,
            'min_version' => $min_version
        ];
        
        // Update latest version if newer
        if (empty($this->manifest_data['latest_version']) || 
            version_compare($version, $this->manifest_data['latest_version'], '>')) {
            $this->manifest_data['latest_version'] = $version;
        }
        
        // Save manifest
        $this->saveManifest();
        
        // Copy package to packages directory
        if (!file_exists($this->packages_dir)) {
            mkdir($this->packages_dir, 0755, true);
        }
        copy($package_file, $this->packages_dir . basename($package_file));
        
        return $checksum;
    }
    
    public function removePackage($version) {
        if (isset($this->manifest_data['packages'][$version])) {
            $package_file = $this->packages_dir . basename($this->manifest_data['packages'][$version]['url']);
            if (file_exists($package_file)) {
                unlink($package_file);
            }
            
            unset($this->manifest_data['packages'][$version]);
            
            // Update latest version if needed
            if ($this->manifest_data['latest_version'] === $version) {
                $versions = array_keys($this->manifest_data['packages']);
                $this->manifest_data['latest_version'] = !empty($versions) ? max($versions) : '';
            }
            
            $this->saveManifest();
            return true;
        }
        return false;
    }
    
    public function verifyPackage($version, $package_file) {
        if (!isset($this->manifest_data['packages'][$version])) {
            throw new Exception("Version not found in manifest");
        }
        
        $expected_checksum = $this->manifest_data['packages'][$version]['checksum'];
        $actual_checksum = md5_file($package_file);
        
        return $expected_checksum === $actual_checksum;
    }
    
    public function verifyAllPackages() {
        $results = [];
        foreach ($this->manifest_data['packages'] as $version => $info) {
            $package_file = $this->packages_dir . basename($info['url']);
            try {
                $valid = file_exists($package_file) && $this->verifyPackage($version, $package_file);
                $results[$version] = [
                    'valid' => $valid,
                    'error' => $valid ? null : 'Checksum mismatch or file missing'
                ];
            } catch (Exception $e) {
                $results[$version] = [
                    'valid' => false,
                    'error' => $e->getMessage()
                ];
            }
        }
        return $results;
    }
    
    public function updateMetadata($version, $data) {
        if (!isset($this->manifest_data['packages'][$version])) {
            throw new Exception("Version not found in manifest");
        }
        
        // Update package metadata
        $allowed_fields = ['release_date', 'changelog', 'requirements'];
        foreach ($allowed_fields as $field) {
            if (isset($data[$field])) {
                $this->manifest_data[$field] = $data[$field];
            }
        }
        
        $this->saveManifest();
    }
    
    private function saveManifest() {
        file_put_contents(
            $this->manifest_file, 
            json_encode($this->manifest_data, JSON_PRETTY_PRINT)
        );
    }
    
    public function generateChecksumReport() {
        $report = "Update Packages Checksum Report\n";
        $report .= "Generated: " . date('Y-m-d H:i:s') . "\n\n";
        
        $results = $this->verifyAllPackages();
        
        foreach ($results as $version => $info) {
            $report .= "Version: $version\n";
            $report .= "Status: " . ($info['valid'] ? 'Valid' : 'Invalid') . "\n";
            if (!$info['valid']) {
                $report .= "Error: " . $info['error'] . "\n";
            }
            if (isset($this->manifest_data['packages'][$version]['checksum'])) {
                $report .= "Checksum: " . $this->manifest_data['packages'][$version]['checksum'] . "\n";
            }
            $report .= "\n";
        }
        
        return $report;
    }
}

// CLI interface for managing updates
if (php_sapi_name() === 'cli') {
    if ($argc < 2) {
        echo "Usage:\n";
        echo "  php checksum_manager.php add <version> <package_file> [min_version]\n";
        echo "  php checksum_manager.php remove <version>\n";
        echo "  php checksum_manager.php verify <version> <package_file>\n";
        echo "  php checksum_manager.php verify-all\n";
        echo "  php checksum_manager.php report\n";
        exit(1);
    }

    $manager = new ChecksumManager();
    $command = $argv[1];

    try {
        switch ($command) {
            case 'add':
                if ($argc < 4) {
                    throw new Exception("Missing required arguments");
                }
                $checksum = $manager->addPackage($argv[2], $argv[3], $argc > 4 ? $argv[4] : null);
                echo "Package added successfully\n";
                echo "Checksum: $checksum\n";
                break;

            case 'remove':
                if ($argc < 3) {
                    throw new Exception("Missing version argument");
                }
                if ($manager->removePackage($argv[2])) {
                    echo "Package removed successfully\n";
                } else {
                    echo "Package not found\n";
                }
                break;

            case 'verify':
                if ($argc < 4) {
                    throw new Exception("Missing required arguments");
                }
                if ($manager->verifyPackage($argv[2], $argv[3])) {
                    echo "Package verification successful\n";
                } else {
                    echo "Package verification failed\n";
                }
                break;

            case 'verify-all':
                $results = $manager->verifyAllPackages();
                foreach ($results as $version => $info) {
                    echo "Version $version: " . ($info['valid'] ? 'Valid' : 'Invalid') . "\n";
                    if (!$info['valid']) {
                        echo "  Error: " . $info['error'] . "\n";
                    }
                }
                break;

            case 'report':
                echo $manager->generateChecksumReport();
                break;

            default:
                throw new Exception("Unknown command: $command");
        }
    } catch (Exception $e) {
        echo "Error: " . $e->getMessage() . "\n";
        exit(1);
    }
}
?>