<?php

declare(strict_types=1);

namespace App\Framework\Filesystem\Exceptions;

use App\Framework\Exception\Core\FilesystemErrorCode;
use App\Framework\Exception\ExceptionContext;
use App\Framework\Exception\FrameworkException;

/**
 * Base exception for all filesystem-related errors
 *
 * Provides common functionality for file and directory operations errors
 */
abstract class FilesystemException extends FrameworkException
{
    /**
     * Create exception for a file operation
     */
    public static function forPath(
        string $path,
        string $message,
        FilesystemErrorCode $errorCode,
        ?string $operation = null,
        ?\Throwable $previous = null
    ): static {
        $context = ExceptionContext::forOperation(
            $operation ?? 'filesystem.operation',
            'Filesystem'
        )->withData([
            'path' => $path,
            'operation' => $operation,
        ]);

        return static::fromContext($message, $context, $errorCode, previous: $previous);
    }

    /**
     * Create exception with file context
     */
    public static function forFile(
        string $path,
        FilesystemErrorCode $errorCode,
        ?string $reason = null,
        ?\Throwable $previous = null
    ): static {
        $message = $errorCode->getDescription();

        if ($reason) {
            $message .= ": {$reason}";
        }

        return static::forPath(
            $path,
            $message,
            $errorCode,
            'file.operation',
            $previous
        );
    }

    /**
     * Create exception with directory context
     */
    public static function forDirectory(
        string $path,
        FilesystemErrorCode $errorCode,
        ?string $reason = null,
        ?\Throwable $previous = null
    ): static {
        $message = $errorCode->getDescription();

        if ($reason) {
            $message .= ": {$reason}";
        }

        return static::forPath(
            $path,
            $message,
            $errorCode,
            'directory.operation',
            $previous
        );
    }

    /**
     * Get the file path from exception context
     */
    public function getPath(): ?string
    {
        return $this->context->data['path'] ?? null;
    }

    /**
     * Get the operation that failed
     */
    public function getOperation(): ?string
    {
        return $this->context->data['operation'] ?? null;
    }
}
