<?php
namespace App\Core;

use RuntimeException;

class Upload
{
    private const IMAGE_MIMES = ['image/jpeg', 'image/png', 'image/webp', 'image/gif'];
    private const IMAGE_EXTENSIONS = ['jpg', 'jpeg', 'png', 'webp', 'gif'];
    private const AUDIO_MIMES = [
        'audio/mpeg',
        'audio/mp3',
        'audio/wav',
        'audio/x-wav',
        'audio/vnd.wave',
        'audio/ogg',
        'application/ogg',
        'audio/mp4',
        'audio/x-m4a',
        'video/mp4',
        'audio/flac',
        'audio/x-flac',
    ];
    private const MODEL_MIMES = [
        'model/gltf-binary',
        'model/gltf+json',
        'model/vnd.usdz+zip',
        'application/octet-stream',
        'application/json',
        'text/plain',
        'application/zip',
    ];

    public static function validImage(array $file): bool
    {
        return isset($file['tmp_name']) && in_array(mime_content_type($file['tmp_name']), ['image/jpeg', 'image/png', 'image/webp', 'image/gif'], true);
    }

    public static function storeImage(array $file, string $targetPath, int $maxMb = 12): string
    {
        return self::store($file, $targetPath, self::IMAGE_EXTENSIONS, self::IMAGE_MIMES, $maxMb);
    }

    public static function storeAudio(array $file, string $targetPath, array $allowedExtensions, int $maxMb = 100): string
    {
        $allowedExtensions = array_values(array_intersect(
            array_map('strtolower', $allowedExtensions ?: ['mp3', 'wav', 'ogg', 'm4a', 'flac']),
            ['mp3', 'wav', 'ogg', 'm4a', 'flac']
        ));

        return self::store($file, $targetPath, $allowedExtensions, self::AUDIO_MIMES, $maxMb);
    }

    public static function storeModel(array $file, string $targetPath, array $allowedExtensions, int $maxMb = 100): string
    {
        $allowedExtensions = array_values(array_intersect(
            array_map('strtolower', $allowedExtensions ?: ['glb', 'gltf', 'usdz']),
            ['glb', 'gltf', 'usdz']
        ));

        return self::store($file, $targetPath, $allowedExtensions, self::MODEL_MIMES, $maxMb);
    }

    public static function normalizeMultiple(array $files): array
    {
        if (!isset($files['name'])) {
            return [];
        }

        if (!is_array($files['name'])) {
            return [$files];
        }

        $normalized = [];
        foreach ($files['name'] as $index => $name) {
            $normalized[] = [
                'name' => $name,
                'type' => $files['type'][$index] ?? '',
                'tmp_name' => $files['tmp_name'][$index] ?? '',
                'error' => $files['error'][$index] ?? UPLOAD_ERR_NO_FILE,
                'size' => $files['size'][$index] ?? 0,
            ];
        }

        return $normalized;
    }

    private static function store(array $file, string $targetPath, array $extensions, array $mimes, int $maxMb): string
    {
        if (($file['error'] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_NO_FILE) {
            throw new RuntimeException('Dosya secilmedi.');
        }

        if (($file['error'] ?? UPLOAD_ERR_OK) !== UPLOAD_ERR_OK) {
            throw new RuntimeException('Dosya yuklenemedi.');
        }

        $tmp = (string) ($file['tmp_name'] ?? '');
        if ($tmp === '' || !is_file($tmp)) {
            throw new RuntimeException('Gecersiz gecici dosya.');
        }

        $size = (int) ($file['size'] ?? 0);
        if ($size <= 0 || $size > ($maxMb * 1024 * 1024)) {
            throw new RuntimeException('Dosya boyutu limiti asildi. Maksimum ' . $maxMb . ' MB.');
        }

        $original = (string) ($file['name'] ?? 'upload');
        $extension = strtolower(pathinfo($original, PATHINFO_EXTENSION));
        if (!in_array($extension, $extensions, true)) {
            throw new RuntimeException('Bu dosya uzantisi desteklenmiyor.');
        }

        $mime = mime_content_type($tmp) ?: '';
        if (!in_array($mime, $mimes, true)) {
            throw new RuntimeException('Dosya MIME tipi guvenli degil: ' . $mime);
        }

        [$absoluteDir, $webDir] = self::targetDirs($targetPath);
        if (!is_dir($absoluteDir) && !mkdir($absoluteDir, 0775, true) && !is_dir($absoluteDir)) {
            throw new RuntimeException('Upload klasoru olusturulamadi.');
        }

        $baseName = strtolower(pathinfo($original, PATHINFO_FILENAME));
        $baseName = preg_replace('~[^a-z0-9]+~', '-', $baseName) ?: 'upload';
        $baseName = trim($baseName, '-') ?: 'upload';
        $fileName = substr($baseName, 0, 70) . '-' . date('YmdHis') . '-' . bin2hex(random_bytes(4)) . '.' . $extension;
        $target = rtrim($absoluteDir, '/\\') . DIRECTORY_SEPARATOR . $fileName;

        if (!move_uploaded_file($tmp, $target) && !rename($tmp, $target)) {
            throw new RuntimeException('Dosya kaydedilemedi.');
        }

        return rtrim($webDir, '/') . '/' . $fileName;
    }

    private static function targetDirs(string $targetPath): array
    {
        $targetPath = trim($targetPath);
        if ($targetPath === '') {
            $targetPath = '/public/uploads/';
        }

        $normalized = str_replace('\\', '/', $targetPath);
        $base = defined('BASE_PATH') ? BASE_PATH : dirname(__DIR__, 2);

        if (str_starts_with($normalized, '/public/')) {
            $absolute = $base . $normalized;
            $web = substr($normalized, strlen('/public'));
        } elseif (str_starts_with($normalized, '/uploads/')) {
            $absolute = $base . '/public' . $normalized;
            $web = $normalized;
        } elseif (preg_match('~^[A-Za-z]:/~', $normalized) || str_starts_with($normalized, '/')) {
            $absolute = $targetPath;
            $publicRoot = str_replace('\\', '/', $base . '/public');
            $web = str_starts_with(str_replace('\\', '/', $absolute), $publicRoot)
                ? substr(str_replace('\\', '/', $absolute), strlen($publicRoot))
                : '/uploads';
        } else {
            $absolute = $base . '/public/uploads/' . trim($normalized, '/');
            $web = '/uploads/' . trim($normalized, '/');
        }

        return [rtrim($absolute, '/\\'), '/' . trim($web, '/')];
    }
}
