<?php

/**
 * Хелпер для роботи з завантаженням файлів
 * Обгортка над Upload класом
 *
 * @package Flowaxy\Support\Helpers
 * @version 1.0.0 Alpha prerelease
 */

declare(strict_types=1);

namespace Flowaxy\Support\Helpers;

use Flowaxy\Infrastructure\Filesystem\Upload;

final class UploadHelper
{
    /**
     * Обробити завантаження файлу
     *
     * @param array<string, mixed>|string $file
     * @param string|null $uploadDir
     * @return array<string, mixed>|false
     */
    public static function handle(array|string $file, ?string $uploadDir = null): array|false
    {
        $upload = new Upload($uploadDir);

        if (is_string($file)) {
            $file = $_FILES[$file] ?? [];
        }

        if (empty($file) || !isset($file['tmp_name'])) {
            return false;
        }

        return $upload->handle($file);
    }

    /**
     * Валідувати файл
     *
     * @param array<string, mixed> $file
     * @param array<int, string>|null $allowedExtensions
     * @param int|null $maxSize
     * @return bool
     */
    public static function validate(array $file, ?array $allowedExtensions = null, ?int $maxSize = null): bool
    {
        $upload = new Upload();

        if ($allowedExtensions !== null) {
            $upload->setAllowedExtensions($allowedExtensions);
        }

        if ($maxSize !== null) {
            $upload->setMaxFileSize($maxSize);
        }

        return $upload->validate($file);
    }

    /**
     * Перемістити завантажений файл
     *
     * @param array<string, mixed> $file
     * @param string $destination
     * @return bool
     */
    public static function move(array $file, string $destination): bool
    {
        if (!isset($file['tmp_name']) || !is_uploaded_file($file['tmp_name'])) {
            return false;
        }

        FileHelper::makeDirectory(dirname($destination), 0755, true);

        return move_uploaded_file($file['tmp_name'], $destination);
    }

    /**
     * Зберегти завантажений файл
     *
     * @param array<string, mixed> $file
     * @param string $uploadDir
     * @param string|null $filename
     * @return string|false
     */
    public static function store(array $file, string $uploadDir, ?string $filename = null): string|false
    {
        $upload = new Upload($uploadDir);

        if ($filename !== null) {
            $upload->setNamingStrategy('custom');
        }

        $result = $upload->handle($file);
        if ($result === false) {
            return false;
        }

        return $result['path'] ?? false;
    }

    /**
     * Отримати оригінальне ім'я файлу
     *
     * @param array<string, mixed> $file
     * @return string
     */
    public static function getOriginalName(array $file): string
    {
        return $file['name'] ?? '';
    }

    /**
     * Отримати MIME тип файлу
     *
     * @param array<string, mixed> $file
     * @return string
     */
    public static function getMimeType(array $file): string
    {
        return $file['type'] ?? '';
    }

    /**
     * Отримати розмір файлу
     *
     * @param array<string, mixed> $file
     * @return int
     */
    public static function getSize(array $file): int
    {
        return $file['size'] ?? 0;
    }

    /**
     * Отримати розширення файлу
     *
     * @param array<string, mixed> $file
     * @return string
     */
    public static function getExtension(array $file): string
    {
        $name = self::getOriginalName($file);

        return FileHelper::extension($name);
    }

    /**
     * Перевірити, чи файл валідний
     *
     * @param array<string, mixed> $file
     * @return bool
     */
    public static function isValid(array $file): bool
    {
        return isset($file['tmp_name']) && is_uploaded_file($file['tmp_name']) && $file['error'] === UPLOAD_ERR_OK;
    }

    /**
     * Отримати помилку завантаження
     *
     * @param array<string, mixed> $file
     * @return string
     */
    public static function getError(array $file): string
    {
        $error = $file['error'] ?? UPLOAD_ERR_OK;

        return match ($error) {
            UPLOAD_ERR_OK => '',
            UPLOAD_ERR_INI_SIZE => 'Файл перевищує максимальний розмір, встановлений в php.ini',
            UPLOAD_ERR_FORM_SIZE => 'Файл перевищує максимальний розмір, встановлений у формі',
            UPLOAD_ERR_PARTIAL => 'Файл був завантажений лише частково',
            UPLOAD_ERR_NO_FILE => 'Файл не був завантажений',
            UPLOAD_ERR_NO_TMP_DIR => 'Відсутня тимчасова директорія',
            UPLOAD_ERR_CANT_WRITE => 'Не вдалося записати файл на диск',
            UPLOAD_ERR_EXTENSION => 'Розширення PHP зупинило завантаження файлу',
            default => 'Невідома помилка завантаження',
        };
    }

    /**
     * Перевірити, чи файл є зображенням
     *
     * @param array<string, mixed> $file
     * @return bool
     */
    public static function isImage(array $file): bool
    {
        $mimeType = self::getMimeType($file);
        $allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml'];

        return in_array($mimeType, $allowedTypes, true);
    }

    /**
     * Перевірити, чи файл є документом
     *
     * @param array<string, mixed> $file
     * @return bool
     */
    public static function isDocument(array $file): bool
    {
        $mimeType = self::getMimeType($file);
        $allowedTypes = [
            'application/pdf',
            'application/msword',
            'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
            'application/vnd.ms-excel',
            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        ];

        return in_array($mimeType, $allowedTypes, true);
    }

    /**
     * Перевірити, чи файл є відео
     *
     * @param array<string, mixed> $file
     * @return bool
     */
    public static function isVideo(array $file): bool
    {
        $mimeType = self::getMimeType($file);

        return str_starts_with($mimeType, 'video/');
    }

    /**
     * Перевірити, чи файл є аудіо
     *
     * @param array<string, mixed> $file
     * @return bool
     */
    public static function isAudio(array $file): bool
    {
        $mimeType = self::getMimeType($file);

        return str_starts_with($mimeType, 'audio/');
    }
}
