package com.test.bijihoudaun.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.test.bijihoudaun.common.exception.BusinessException;
import com.test.bijihoudaun.entity.Image;
import com.test.bijihoudaun.mapper.ImageMapper;
import com.test.bijihoudaun.service.ImageService;
import com.test.bijihoudaun.util.ImageCompressor;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

@Service
@Transactional
public class ImageServiceImpl
        extends ServiceImpl<ImageMapper, Image>
        implements ImageService {

    private static final Set<String> ALLOWED_EXTENSIONS = Set.of(
            ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp", ".svg"
    );

    private static final long MAX_FILE_SIZE = 10 * 1024 * 1024;

    private static final Map<String, byte[]> FILE_SIGNATURES = Map.ofEntries(
            Map.entry("jpg", new byte[]{(byte)0xFF, (byte)0xD8, (byte)0xFF}),
            Map.entry("jpeg", new byte[]{(byte)0xFF, (byte)0xD8, (byte)0xFF}),
            Map.entry("png", new byte[]{(byte)0x89, 0x50, 0x4E, 0x47}),
            Map.entry("gif", new byte[]{0x47, 0x49, 0x46}),
            Map.entry("bmp", new byte[]{0x42, 0x4D}),
            Map.entry("webp", new byte[]{0x52, 0x49, 0x46, 0x46})
    );

    @Value("${file.upload-dir}")
    private String uploadDir;
    @Resource
    private ImageMapper imageMapper;

    @Override
    public Image uploadImage( MultipartFile file, Long userId, Long markdownId) throws IOException {
        if (file == null || file.isEmpty()) {
            throw new BusinessException("上传文件不能为空");
        }
        
        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null || originalFilename.isEmpty()) {
            throw new BusinessException("文件名无效");
        }
        
        if (file.getSize() > MAX_FILE_SIZE) {
            throw new BusinessException("文件大小超过限制（最大10MB）");
        }
        
        int lastDotIndex = originalFilename.lastIndexOf(".");
        if (lastDotIndex == -1) {
            throw new BusinessException("文件缺少扩展名");
        }
        
        String extension = originalFilename.substring(lastDotIndex).toLowerCase();
        if (!ALLOWED_EXTENSIONS.contains(extension)) {
            throw new BusinessException("不支持的文件类型，仅支持图片文件");
        }
        
        String contentType = file.getContentType();
        if (contentType == null || !contentType.startsWith("image/")) {
            throw new BusinessException("文件内容类型无效");
        }

        // 验证文件头
        String extWithoutDot = extension.substring(1).toLowerCase();
        if (!validateFileSignature(file, extWithoutDot)) {
            throw new BusinessException("文件内容与扩展名不匹配，可能是伪装的恶意文件");
        }

        Path uploadPath = Paths.get(uploadDir);
        if (!Files.exists(uploadPath)) {
            Files.createDirectories(uploadPath);
        }

        String storedName = UUID.randomUUID() + extension;

        Path filePath = uploadPath.resolve(storedName);

        // 优化：压缩图片后再保存，确保流关闭
        try (InputStream originalStream = file.getInputStream()) {
            InputStream compressedStream = ImageCompressor.compressIfNeeded(
                    originalStream, contentType, file.getSize());

            if (compressedStream != null) {
                // 使用压缩后的图片
                try (compressedStream) {
                    Files.copy(compressedStream, filePath);
                }
            } else {
                // 使用原图，需要重新获取流
                try (InputStream newStream = file.getInputStream()) {
                    Files.copy(newStream, filePath);
                }
            }
        }

        Image image = new Image();
        image.setOriginalName(originalFilename);
        image.setStoredName(storedName);
        // 返回相对路径，前端会根据环境自动拼接 baseURL
        image.setUrl("/api/images/preview/" + storedName);
        image.setSize(file.getSize());
        image.setContentType(contentType);
        image.setCreatedAt(new Date());
        image.setMarkdownId(markdownId);

        this.save(image);
        return image;
    }

    private boolean validateFileSignature(MultipartFile file, String extension) throws IOException {
        byte[] signature = FILE_SIGNATURES.get(extension);
        if (signature == null) return true;

        byte[] fileHeader = new byte[Math.max(4, signature.length)];
        try (InputStream is = file.getInputStream()) {
            int read = is.read(fileHeader);
            if (read < signature.length) return false;
            return Arrays.equals(Arrays.copyOf(fileHeader, signature.length), signature);
        }
    }

    @Override
    public boolean deleteImage(Long id) {
        Image image = imageMapper.selectById(id);
        if (ObjectUtil.isNull(image)) {
            return false;
        }
        try {
            Path filePath = Paths.get(uploadDir, image.getStoredName());
            Files.deleteIfExists(filePath);

            this.removeById(id);
            return true;
        } catch (IOException e) {
            throw new RuntimeException("删除图片失败", e);
        }
    }

    @Override
    public boolean deleteImageByUrl(String url) {
        Image image = imageMapper.selectOne(new QueryWrapper<Image>().eq("url", url));
        if (ObjectUtil.isNull(image)) {
            return false;
        }
        try {
            Path filePath = Paths.get(uploadDir, image.getStoredName());
            Files.deleteIfExists(filePath);

            this.removeById(image.getId());
            return true;
        } catch (IOException e) {
            throw new RuntimeException("删除图片失败", e);
        }
    }
    @Override
    public boolean deleteImageByUrls(List<String> urls) {
        if (CollUtil.isEmpty(urls)) {
            return false;
        }
        // 批量查询，避免N+1问题
        List<Image> images = imageMapper.selectList(new QueryWrapper<Image>().in("url", urls));
        if (CollUtil.isEmpty(images)) {
            return false;
        }
        
        // 批量删除文件和数据库记录
        for (Image image : images) {
            try {
                Path filePath = Paths.get(uploadDir, image.getStoredName());
                Files.deleteIfExists(filePath);
            } catch (IOException e) {
                throw new RuntimeException("删除图片文件失败: " + image.getStoredName(), e);
            }
        }
        
        // 批量删除数据库记录
        List<Long> ids = images.stream().map(Image::getId).toList();
        this.removeByIds(ids);
        return true;
    }
}
