<?php

namespace App\Services;

use App\Http\Responses\ApiResponse;
use App\Models\Attachment;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

class AttachmentService
{
    protected ?array $uploadConfig = null;

    protected function getUploadConfig(): array
    {
        if ($this->uploadConfig !== null) {
            return $this->uploadConfig;
        }

        $codes = [
            'upload_image_max_size',
            'upload_file_max_size',
            'upload_video_max_size',
            'upload_image_extensions',
            'upload_file_extensions',
            'upload_video_extensions',
            'upload_hash_check',
        ];

        $dbValues = DB::table('config_items')
            ->whereIn('code', $codes)
            ->where('status', 1)
            ->pluck('value', 'code')
            ->toArray();

        $fallback = config('cmspro.upload', []);

        $this->uploadConfig = [
            'image_max_size' => isset($dbValues['upload_image_max_size'])
                ? (int) $dbValues['upload_image_max_size']
                : ($fallback['image_max_size'] ?? 5120),
            'file_max_size' => isset($dbValues['upload_file_max_size'])
                ? (int) $dbValues['upload_file_max_size']
                : ($fallback['file_max_size'] ?? 20480),
            'video_max_size' => isset($dbValues['upload_video_max_size'])
                ? (int) $dbValues['upload_video_max_size']
                : ($fallback['video_max_size'] ?? 102400),
            'image_extensions' => isset($dbValues['upload_image_extensions'])
                ? array_filter(array_map('trim', explode(',', $dbValues['upload_image_extensions'])))
                : ($fallback['allowed_extensions']['image'] ?? ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']),
            'file_extensions' => isset($dbValues['upload_file_extensions'])
                ? array_filter(array_map('trim', explode(',', $dbValues['upload_file_extensions'])))
                : ($fallback['allowed_extensions']['file'] ?? ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'zip', 'rar']),
            'video_extensions' => isset($dbValues['upload_video_extensions'])
                ? array_filter(array_map('trim', explode(',', $dbValues['upload_video_extensions'])))
                : ($fallback['allowed_extensions']['video'] ?? ['mp4', 'mp3']),
            'hash_check' => isset($dbValues['upload_hash_check'])
                ? ($dbValues['upload_hash_check'] === '1' || $dbValues['upload_hash_check'] === 'true')
                : true,
        ];

        return $this->uploadConfig;
    }

    public function getUploadConfigForFrontend(): array
    {
        $config = $this->getUploadConfig();

        return [
            'image_max_size' => $config['image_max_size'],
            'file_max_size' => $config['file_max_size'],
            'video_max_size' => $config['video_max_size'],
            'image_extensions' => $config['image_extensions'],
            'file_extensions' => $config['file_extensions'],
            'video_extensions' => $config['video_extensions'],
            'hash_check' => $config['hash_check'],
            'image_max_size_mb' => round($config['image_max_size'] / 1024, 1),
            'file_max_size_mb' => round($config['file_max_size'] / 1024, 1),
            'video_max_size_mb' => round($config['video_max_size'] / 1024, 1),
        ];
    }

    public function index(array $params)
    {
        $query = Attachment::with(['user:id,username,name', 'attachmentGroup:id,name']);

        if (! empty($params['keyword'])) {
            $query->where('name', 'like', "%{$params['keyword']}%");
        }

        if (! empty($params['category'])) {
            $query->where('category', $params['category']);
        }

        if (isset($params['group_id']) && $params['group_id'] !== '') {
            if ($params['group_id'] === '0' || $params['group_id'] === 0) {
                $query->whereNull('group_id');
            } else {
                $query->where('group_id', $params['group_id']);
            }
        }

        if (! empty($params['start_date'])) {
            $query->where('create_time', '>=', $params['start_date'].' 00:00:00');
        }

        if (! empty($params['end_date'])) {
            $query->where('create_time', '<=', $params['end_date'].' 23:59:59');
        }

        $perPage = $params['per_page'] ?? config('cmspro.pagination.per_page', 15);
        $paginator = $query->orderBy('id', 'desc')->paginate($perPage);

        return ApiResponse::paginate($paginator);
    }

    public function upload(UploadedFile $file, ?int $groupId = null): array
    {
        $extension = strtolower($file->getClientOriginalExtension());
        $category = $this->getCategoryByExtension($extension);

        $validationError = $this->validateFile($file, $extension, $category);
        if ($validationError) {
            return $validationError;
        }

        $config = $this->getUploadConfig();

        if ($config['hash_check']) {
            $hash = md5_file($file->getRealPath());
            $existing = Attachment::where('hash', $hash)->first();
            if ($existing) {
                return ApiResponse::success($existing, '文件已存在，直接返回');
            }
        } else {
            $hash = md5_file($file->getRealPath());
        }

        $datePath = date('Y/m/d');
        $fileName = Str::random(40).'.'.$extension;
        $path = $file->storeAs($datePath, $fileName, 'public_uploads');

        $attachment = Attachment::create([
            'user_id' => (auth('admin')->check() ? auth('admin')->id() : (auth('developer')->check() ? auth('developer')->id() : null)),
            'name' => $file->getClientOriginalName(),
            'path' => $path,
            'url' => '/uploads/'.$path,
            'mime_type' => $file->getMimeType(),
            'extension' => $extension,
            'size' => $file->getSize(),
            'hash' => $hash,
            'disk' => 'public_uploads',
            'category' => $category,
            'group_id' => $groupId,
            'status' => 1,
        ]);

        return ApiResponse::success($attachment->load(['user:id,username,name', 'attachmentGroup:id,name']), '上传成功');
    }

    public function show(int $id): array
    {
        $attachment = Attachment::with(['user:id,username,name', 'attachmentGroup:id,name'])->find($id);

        if (! $attachment) {
            return ApiResponse::error(40302, '附件不存在');
        }

        return ApiResponse::success($attachment);
    }

    public function destroy(array $ids): array
    {
        $attachments = Attachment::whereIn('id', $ids)->get();

        if ($attachments->isEmpty()) {
            return ApiResponse::error(40302, '未找到指定附件');
        }

        DB::transaction(function () use ($attachments) {
            foreach ($attachments as $attachment) {
                if (Storage::disk($attachment->disk)->exists($attachment->path)) {
                    Storage::disk($attachment->disk)->delete($attachment->path);
                }
                $attachment->delete();
            }
        });

        return ApiResponse::success(null, '删除成功');
    }

    public function moveGroup(array $ids, ?int $groupId = null): array
    {
        $count = Attachment::whereIn('id', $ids)->update(['group_id' => $groupId]);

        return ApiResponse::success(null, "已移动 {$count} 个附件");
    }

    public function getStats(): array
    {
        $stats = [
            'image' => Attachment::where('category', 'image')->count(),
            'file' => Attachment::where('category', 'file')->count(),
            'video' => Attachment::where('category', 'video')->count(),
            'total' => Attachment::count(),
        ];

        return ApiResponse::success($stats);
    }

    protected function getCategoryByExtension(string $extension): string
    {
        $config = $this->getUploadConfig();

        if (in_array($extension, $config['image_extensions'])) {
            return 'image';
        }

        if (in_array($extension, $config['video_extensions'])) {
            return 'video';
        }

        return 'file';
    }

    protected function validateFile(UploadedFile $file, string $extension, string $category): ?array
    {
        $config = $this->getUploadConfig();

        $allAllowed = array_merge($config['image_extensions'], $config['file_extensions'], $config['video_extensions']);

        if (! in_array($extension, $allAllowed)) {
            return ApiResponse::error(40201, "不支持的文件类型：{$extension}");
        }

        $maxSizeKey = "{$category}_max_size";
        $maxSize = $config[$maxSizeKey] ?? 20480;

        if ($maxSize > 0 && $file->getSize() > $maxSize * 1024) {
            $maxMB = round($maxSize / 1024, 1);

            return ApiResponse::error(40201, "文件大小超过限制（最大 {$maxMB}MB）");
        }

        return null;
    }
}
