<?php

declare(strict_types=1);

namespace App\Framework\Database\Backup;

use App\Framework\Core\ValueObjects\Byte;
use App\Framework\Filesystem\ValueObjects\FilePath;

/**
 * Metadata for backup files
 */
final readonly class BackupMetadata
{
    public function __construct(
        public FilePath|string $filename,
        public Byte $originalSize,
        public Byte $compressedSize,
        public bool $encrypted,
        public bool $compressed,
        public string $checksum,
        public string $createdAt,
        public BackupOptions $options
    ) {
    }

    /**
     * Get filename as FilePath object
     */
    public function getFilePath(): FilePath
    {
        return $this->filename instanceof FilePath ? $this->filename : FilePath::create($this->filename);
    }

    /**
     * Get filename as string
     */
    public function getFilename(): string
    {
        return $this->filename instanceof FilePath ? $this->filename->getFilename() : basename($this->filename);
    }

    /**
     * Get compression ratio as percentage
     */
    public function getCompressionRatio(): float
    {
        if ($this->originalSize->isEmpty()) {
            return 0.0;
        }

        return 100 - $this->compressedSize->percentOf($this->originalSize);
    }

    /**
     * Get space saved by compression
     */
    public function getSpaceSaved(): Byte
    {
        if ($this->originalSize->lessThan($this->compressedSize)) {
            return Byte::zero();
        }

        return $this->originalSize->subtract($this->compressedSize);
    }

    /**
     * Check if backup is efficiently compressed (>10% reduction)
     */
    public function isEfficientlyCompressed(): bool
    {
        return $this->getCompressionRatio() > 10.0;
    }

    /**
     * Get backup summary string
     */
    public function getSummary(): string
    {
        $parts = [];

        if ($this->compressed) {
            $ratio = round($this->getCompressionRatio(), 1);
            $parts[] = "compressed ({$ratio}%)";
        }

        if ($this->encrypted) {
            $parts[] = "encrypted";
        }

        $status = empty($parts) ? 'plain' : implode(', ', $parts);

        return "{$this->compressedSize->toHumanReadable()} ({$status})";
    }

    /**
     * @return array{filename: string, originalSize: int, compressedSize: int, encrypted: bool, compressed: bool, checksum: string, createdAt: string, options: array}
     * Convert to array for serialization
     */
    public function toArray(): array
    {
        return [
            'filename' => $this->filename instanceof FilePath ? $this->filename->toString() : $this->filename,
            'originalSize' => $this->originalSize->toBytes(),
            'compressedSize' => $this->compressedSize->toBytes(),
            'encrypted' => $this->encrypted,
            'compressed' => $this->compressed,
            'checksum' => $this->checksum,
            'createdAt' => $this->createdAt,
            'options' => $this->options->toArray(),
        ];
    }

    /**
     * Create from an array (for JSON deserialization)
     */
    public static function fromArray(array $data): self
    {
        return new self(
            filename: $data['filename'],
            originalSize: Byte::fromBytes($data['originalSize']),
            compressedSize: Byte::fromBytes($data['compressedSize']),
            encrypted: $data['encrypted'],
            compressed: $data['compressed'],
            checksum: $data['checksum'],
            createdAt: $data['createdAt'],
            options: BackupOptions::fromArray($data['options'])
        );
    }
}
