<?php

declare(strict_types=1);

namespace App\Framework\Filesystem\ValueObjects;

use App\Framework\Core\ValueObjects\FileSize;
use App\Framework\Core\ValueObjects\Timestamp;

/**
 * Context für eine Filesystem-Operation
 *
 * Speichert Metadaten über die durchgeführte Operation
 * für Logging, Monitoring und Debugging
 */
final readonly class FileOperationContext
{
    public function __construct(
        public FileOperation $operation,
        public string $path,
        public ?string $destinationPath = null,
        public ?FileSize $bytesAffected = null,
        public ?Timestamp $timestamp = null,
        public ?string $userId = null,
        public ?array $metadata = null
    ) {
    }

    /**
     * Factory für einfache Operation ohne Destination
     */
    public static function forOperation(
        FileOperation $operation,
        string $path
    ): self {
        return new self(
            operation: $operation,
            path: $path,
            timestamp: Timestamp::now()
        );
    }

    /**
     * Factory für Operation mit Destination (Copy, Move)
     */
    public static function forOperationWithDestination(
        FileOperation $operation,
        string $sourcePath,
        string $destinationPath
    ): self {
        return new self(
            operation: $operation,
            path: $sourcePath,
            destinationPath: $destinationPath,
            timestamp: Timestamp::now()
        );
    }

    /**
     * Factory für Write-Operation mit Bytes
     */
    public static function forWrite(
        string $path,
        FileSize $bytesWritten,
        ?string $userId = null
    ): self {
        return new self(
            operation: FileOperation::WRITE,
            path: $path,
            bytesAffected: $bytesWritten,
            timestamp: Timestamp::now(),
            userId: $userId
        );
    }

    /**
     * Factory für Read-Operation mit Bytes
     */
    public static function forRead(
        string $path,
        FileSize $bytesRead
    ): self {
        return new self(
            operation: FileOperation::READ,
            path: $path,
            bytesAffected: $bytesRead,
            timestamp: Timestamp::now()
        );
    }

    /**
     * Mit zusätzlichen Metadaten
     */
    public function withMetadata(array $metadata): self
    {
        return new self(
            operation: $this->operation,
            path: $this->path,
            destinationPath: $this->destinationPath,
            bytesAffected: $this->bytesAffected,
            timestamp: $this->timestamp,
            userId: $this->userId,
            metadata: array_merge($this->metadata ?? [], $metadata)
        );
    }

    /**
     * Mit User ID
     */
    public function withUserId(string $userId): self
    {
        return new self(
            operation: $this->operation,
            path: $this->path,
            destinationPath: $this->destinationPath,
            bytesAffected: $this->bytesAffected,
            timestamp: $this->timestamp,
            userId: $userId,
            metadata: $this->metadata
        );
    }

    /**
     * Konvertiert zu Array für Logging
     */
    public function toArray(): array
    {
        $data = [
            'operation' => $this->operation->value,
            'operation_name' => $this->operation->toOperationName(),
            'path' => $this->path,
            'timestamp' => $this->timestamp?->toIso8601String(),
            'severity' => $this->operation->getSeverity(),
        ];

        if ($this->destinationPath !== null) {
            $data['destination_path'] = $this->destinationPath;
        }

        if ($this->bytesAffected !== null) {
            $data['bytes_affected'] = $this->bytesAffected->toBytes();
            $data['bytes_affected_human'] = $this->bytesAffected->toHumanReadable();
        }

        if ($this->userId !== null) {
            $data['user_id'] = $this->userId;
        }

        if ($this->metadata !== null && !empty($this->metadata)) {
            $data['metadata'] = $this->metadata;
        }

        return $data;
    }

    /**
     * Gibt lesbare String-Repräsentation zurück
     */
    public function toString(): string
    {
        $parts = [
            $this->operation->getDescription(),
            "path: {$this->path}",
        ];

        if ($this->destinationPath !== null) {
            $parts[] = "destination: {$this->destinationPath}";
        }

        if ($this->bytesAffected !== null) {
            $parts[] = "bytes: {$this->bytesAffected->toHumanReadable()}";
        }

        if ($this->userId !== null) {
            $parts[] = "user: {$this->userId}";
        }

        return implode(', ', $parts);
    }

    /**
     * Prüft ob Operation high severity ist
     */
    public function isHighSeverity(): bool
    {
        return $this->operation->getSeverity() === 'high';
    }

    /**
     * Prüft ob Operation Write-Operation war
     */
    public function isWriteOperation(): bool
    {
        return $this->operation->isWriteOperation();
    }

    /**
     * Prüft ob große Datenmenge betroffen ist (>10MB)
     */
    public function isLargeOperation(): bool
    {
        if ($this->bytesAffected === null) {
            return false;
        }

        return $this->bytesAffected->isLargeFile();
    }
}
