<?php

declare(strict_types=1);

namespace App\Framework\Process\Services;

use App\Framework\Filesystem\ValueObjects\FilePath;
use App\Framework\Process\Process;
use App\Framework\Process\ValueObjects\Backup\BackupFile;
use App\Framework\Process\ValueObjects\Backup\BackupVerificationResult;
use App\Framework\Process\ValueObjects\Command;

/**
 * Backup Verification Service.
 *
 * Verifiziert Backup-Dateien in einem Verzeichnis.
 */
final readonly class BackupVerificationService
{
    public function __construct(
        private Process $process
    ) {
    }

    /**
     * Verifiziert Backups in einem Verzeichnis.
     */
    public function verify(FilePath $backupDirectory, string $pattern = '*.sql'): BackupVerificationResult
    {
        if (! $backupDirectory->isDirectory()) {
            return BackupVerificationResult::fromBackups([]);
        }

        $backups = $this->findBackups($backupDirectory, $pattern);

        return BackupVerificationResult::fromBackups($backups);
    }

    /**
     * Findet Backup-Dateien in einem Verzeichnis.
     *
     * @return BackupFile[]
     */
    private function findBackups(FilePath $directory, string $pattern): array
    {
        // Find files matching pattern
        $result = $this->process->run(
            Command::fromString("find {$directory->toString()} -name '{$pattern}' -type f")
        );

        if (! $result->isSuccess() || empty($result->stdout)) {
            return [];
        }

        $filePaths = explode("\n", trim($result->stdout));
        $backups = [];

        foreach ($filePaths as $filePath) {
            if (empty($filePath)) {
                continue;
            }

            $backupFile = $this->createBackupFile(FilePath::create($filePath));
            if ($backupFile !== null) {
                $backups[] = $backupFile;
            }
        }

        // Sort by creation date (newest first)
        usort($backups, fn (BackupFile $a, BackupFile $b) => $b->createdAt <=> $a->createdAt);

        return $backups;
    }

    /**
     * Erstellt ein BackupFile aus einem FilePath.
     */
    private function createBackupFile(FilePath $path): ?BackupFile
    {
        if (! $path->exists() || ! $path->isFile()) {
            return null;
        }

        $size = $path->getSize();
        $modifiedTime = $path->getModifiedTime();

        return new BackupFile(
            path: $path,
            size: $size,
            createdAt: new \DateTimeImmutable('@' . $modifiedTime),
            name: $path->getFilename()
        );
    }

    /**
     * Prüft die Integrität einer Backup-Datei (falls komprimiert).
     */
    public function checkIntegrity(BackupFile $backup): bool
    {
        $extension = $backup->path->getExtension();

        return match ($extension) {
            'gz', 'gzip' => $this->testGzipIntegrity($backup->path),
            'zip' => $this->testZipIntegrity($backup->path),
            default => true, // Unkomprimierte Dateien als OK annehmen
        };
    }

    /**
     * Testet Gzip-Integrität.
     */
    private function testGzipIntegrity(FilePath $file): bool
    {
        $result = $this->process->run(
            Command::fromArray(['gzip', '-t', $file->toString()])
        );

        return $result->isSuccess();
    }

    /**
     * Testet ZIP-Integrität.
     */
    private function testZipIntegrity(FilePath $file): bool
    {
        $result = $this->process->run(
            Command::fromArray(['unzip', '-t', $file->toString()])
        );

        return $result->isSuccess();
    }
}
