<?php

namespace App\Services\System;

use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Intervention\Image\ImageManager;
use Intervention\Image\Drivers\Gd\Driver;

class UploadService
{
    protected $disk;
    protected $allowedImageTypes = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp'];
    protected $allowedFileTypes = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'zip', 'rar', 'txt'];
    protected $maxFileSize = 10 * 1024 * 1024; // 10MB

    public function __construct()
    {
        $this->disk = Storage::disk('public');
        $this->imageManager = new ImageManager(new Driver());
    }

    public function upload(UploadedFile $file, string $directory = 'uploads', array $options = []): array
    {
        $extension = strtolower($file->getClientOriginalExtension());

        if (!$this->validateFile($file, $extension)) {
            throw new \Exception('文件验证失败');
        }

        $fileName = $this->generateFileName($file, $extension);
        $filePath = $directory . '/' . date('Ymd') . '/' . $fileName;

        if (in_array($extension, $this->allowedImageTypes) && isset($options['compress'])) {
            $this->compressImage($file, $filePath, $options);
        } else {
            $this->disk->put($filePath, file_get_contents($file));
        }

        $url = $this->disk->url($filePath);
        $fullPath = $this->disk->path($filePath);

        return [
            'url' => $url,
            'path' => $filePath,
            'name' => $file->getClientOriginalName(),
            'size' => $file->getSize(),
            'mime_type' => $file->getMimeType(),
            'extension' => $extension,
        ];
    }

    public function uploadMultiple(array $files, string $directory = 'uploads', array $options = []): array
    {
        $results = [];
        foreach ($files as $file) {
            if ($file instanceof UploadedFile) {
                $results[] = $this->upload($file, $directory, $options);
            }
        }
        return $results;
    }

    public function uploadBase64(string $base64, string $directory = 'uploads', string $fileName = null): array
    {
        if (preg_match('/^data:image\/(\w+);base64,/', $base64, $matches)) {
            $type = $matches[1];
            $extension = $type;
            $data = substr($base64, strpos($base64, ',') + 1);
            $data = base64_decode($data);

            if (!$data) {
                throw new \Exception('Base64解码失败');
            }

            $fileName = $fileName ?: $this->generateUniqueFileName($extension);
            $filePath = $directory . '/' . date('Ymd') . '/' . $fileName;
            $this->disk->put($filePath, $data);

            return [
                'url' => $this->disk->url($filePath),
                'path' => $filePath,
                'name' => $fileName,
                'size' => strlen($data),
                'mime_type' => 'image/' . $type,
                'extension' => $extension,
            ];
        }

        throw new \Exception('无效的Base64图片数据');
    }

    public function delete(string $path): bool
    {
        if ($this->disk->exists($path)) {
            return $this->disk->delete($path);
        }
        return false;
    }

    public function deleteMultiple(array $paths): bool
    {
        foreach ($paths as $path) {
            $this->delete($path);
        }
        return true;
    }

    private function validateFile(UploadedFile $file, string $extension): bool
    {
        if ($file->getSize() > $this->maxFileSize) {
            throw new \Exception('文件大小超过限制');
        }

        $allowedTypes = array_merge($this->allowedImageTypes, $this->allowedFileTypes);
        if (!in_array($extension, $allowedTypes)) {
            throw new \Exception('不允许的文件类型');
        }

        return true;
    }

    private function generateFileName(UploadedFile $file, string $extension): string
    {
        return uniqid() . '_' . Str::random(6) . '.' . $extension;
    }

    private function generateUniqueFileName(string $extension): string
    {
        return uniqid() . '_' . Str::random(6) . '.' . $extension;
    }

    private function compressImage(UploadedFile $file, string $filePath, array $options): void
    {
        $quality = $options['quality'] ?? 80;
        $width = $options['width'] ?? null;
        $height = $options['height'] ?? null;

        $image = $this->imageManager->read($file);

        if ($width || $height) {
            $image->scale($width, $height);
        }

        $encoded = $image->toJpeg(quality: $quality);
        $this->disk->put($filePath, (string) $encoded);
    }

    public function getFileUrl(string $path): string
    {
        return $this->disk->url($path);
    }

    public function fileExists(string $path): bool
    {
        return $this->disk->exists($path);
    }
}
