package com.seer.teach.common.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.seer.teach.common.enums.ResultCodeEnum;
import com.seer.teach.common.exception.CommonException;
import com.seer.teach.common.exception.FileUploadException;
import com.seer.teach.common.minio.config.MinioConfig;
import com.seer.teach.common.minio.service.MinioService;
import com.seer.teach.common.response.OssImageUploadResp;
import com.seer.teach.common.service.CommonFileService;
import com.seer.teach.common.utils.CommonUtils;
import com.seer.teach.common.utils.FileUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * @Author: Captain
 * @Description:
 * @Date: 2025-05-09 13:34
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class CommonFileServiceImpl implements CommonFileService {

    private final MinioService minioService;

    /**
     * Author: Captain
     * Desc:  上传图片
     * Params: [file]
     * Return: com.seer.teach.common.ResultBean
     * Time: 2025/5/9 16:24
     */
    @Override
    public OssImageUploadResp uploadImage(Integer userId, MultipartFile file) throws FileUploadException {
        try {
            log.info("开始上传文件");
            CommonUtils.isIllegalImageType(file);
            log.info("文件类型合法");
            String fileName = CommonUtils.generateUniqueFileName(userId, file);
            log.info("生成文件名：{} 成功", fileName);
            minioService.upload(MinioConfig.AVATAR_FOlDER, fileName, file.getInputStream(), file.getContentType());
            OssImageUploadResp result = new OssImageUploadResp(MinioConfig.URL + "/" + MinioConfig.BUCKET + "/" + MinioConfig.AVATAR_FOlDER + fileName);
            return result;
        } catch (Exception e) {
            log.error("文件上传异常", e);
            throw new FileUploadException(ResultCodeEnum.FILE_UPLOAD_ERROR);
        }
    }

    @Override
    public OssImageUploadResp uploadEnImage(Integer userId, String imageBase64) throws IOException {
        try {
            MultipartFile file = FileUtils.base64ToMultipart(imageBase64);
            log.info("开始上传编码头像文件");
            CommonUtils.isIllegalImageType(file);
            log.info("头像文件类型合法");
            String fileName = CommonUtils.generateUniqueFileName(userId, file);
            log.info("生成文件名：{} 成功", fileName);
            minioService.upload(MinioConfig.AVATAR_FOlDER, fileName, file.getInputStream(), file.getContentType());
            return new OssImageUploadResp(MinioConfig.URL + "/" + MinioConfig.BUCKET + "/" + MinioConfig.AVATAR_FOlDER + fileName);
        } catch (Exception e) {
            log.error("文件上传异常", e);
            throw new FileUploadException(ResultCodeEnum.FILE_UPLOAD_ERROR);
        }
    }

    /**
     * Author: Captain
     * Desc:   上传微信的QrCode图片内容
     * Params: [bytes, fileName]
     * Return: void
     * Time: 2025/5/9 21:46
     */
    @Override
    public void minioUploadQrCodeImage(byte[] bytes, String fileName) throws FileUploadException {
        ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
        minioService.upload(MinioConfig.WX_QR_CODE_IMAGE_FOlDER, fileName, inputStream, "multipart/form-data");
    }

    /**
     * 批量上传图片文件到OSS存储服务
     *
     * @param userId 用户ID，用于标识上传图片的用户
     * @param files  多个图片文件数组，需要上传的图片文件列表
     * @return List<OssImageUploadResp> 图片上传响应结果列表，包含每个文件的上传信息
     * @throws FileUploadException 文件上传异常，当上传过程中发生错误时抛出
     */
    @Override
    public List<OssImageUploadResp> multiUploadImg(Integer userId, MultipartFile[] files) {
        List<OssImageUploadResp> ossImageUploadRespList = new ArrayList<>();
        // 遍历所有上传文件，逐个进行图片上传处理
        for (MultipartFile file : files) {
            OssImageUploadResp ossImageUploadResp = uploadImage(userId, file);
            ossImageUploadRespList.add(ossImageUploadResp);
        }
        return ossImageUploadRespList;
    }

    /**
     * 上传APK文件到MinIO存储服务
     *
     * @param file 要上传的APK文件，类型为MultipartFile
     * @return 上传成功后的文件访问URL
     * @throws FileUploadException 文件上传失败时抛出异常
     */
    @Override
    public String uploadAPKFile(MultipartFile file) {
        try {
            CommonUtils.isIllegalImageType(file);
            // 获取原始文件名
            String fileName = file.getOriginalFilename();
            if (fileName == null || fileName.trim().isEmpty()) {
                throw new FileUploadException(ResultCodeEnum.FILE_UPLOAD_ERROR, "文件名为空");
            }

            // 获取 Content-Type，如果为空则默认 application/vnd.android.package-archive
            String contentType = Optional.ofNullable(file.getContentType())
                    .filter(ct -> !ct.isEmpty())
                    .orElse("application/vnd.android.package-archive");

            // 上传到 MinIO
            try (InputStream in = file.getInputStream()) {
                minioService.upload(MinioConfig.ANDROID_FOLDER, fileName, in, contentType);
            }

            // 拼接返回文件 URL
            return String.format("%s/%s/%s%s",
                    MinioConfig.URL, MinioConfig.BUCKET, MinioConfig.ANDROID_FOLDER, fileName);
        } catch (Exception e) {
            log.error("uploadAPKFile 失败, 文件名={}", file.getOriginalFilename(), e);
            throw new FileUploadException(ResultCodeEnum.FILE_UPLOAD_ERROR);
        }
    }

    /**
     * 上传广告图片文件
     *
     * @param file 要上传的图片文件，类型为MultipartFile
     * @return 返回上传成功后的文件访问URL地址
     * @throws FileUploadException 当文件上传过程中发生异常时抛出
     */
    @Override
    public String uploadAdvertisingPicture(MultipartFile file) {
        try {
            // 验证图片文件类型是否合法
            CommonUtils.isIllegalImageType(file);
            // 生成唯一的文件名
            String fileName = CommonUtils.generateUniqueFileName(RandomUtil.randomInt(), file);
            // 调用Minio服务上传文件到指定目录
            minioService.upload(MinioConfig.BANNER, fileName, file.getInputStream(), file.getContentType());
            // 构造并返回文件访问URL
            return MinioConfig.URL + "/" + MinioConfig.BUCKET + "/" + MinioConfig.BANNER + fileName;
        } catch (Exception e) {
            log.error("uploadFile 失败, 文件名={}", file.getOriginalFilename(), e);
            throw new FileUploadException(ResultCodeEnum.FILE_UPLOAD_ERROR);
        }
    }

    /**
     * 删除指定文件
     *
     * @param fileName 要删除的文件名
     * @throws CommonException 当文件删除过程中发生异常时抛出
     */
    @Override
    public void deleteFile(String fileName) {
        try {
            log.info("开始删除文件, fileName={}", fileName);
            // 调用 minioService 删除
            minioService.remove(MinioConfig.BUCKET, fileName);
        } catch (Exception e) {
            log.error("文件删除失败, fileName={}", fileName, e);
            throw new CommonException(ResultCodeEnum.FILE_DELETE_ERROR);
        }
    }

    @Override
    public String uploadAiCorrectImage(Integer userId, MultipartFile file) {
        try {
            String fileName = CommonUtils.generateUniqueFileName(userId, file);
            minioService.upload(MinioConfig.AI_CORRECT_FOlDER, fileName, file.getInputStream(), file.getContentType());
            return MinioConfig.URL + "/" + MinioConfig.BUCKET + "/" + MinioConfig.AI_CORRECT_FOlDER + fileName;
        } catch (Exception e) {
            log.error("uploadFile 失败, 文件名={}", file.getOriginalFilename(), e);
            throw new FileUploadException(ResultCodeEnum.FILE_UPLOAD_ERROR);
        }
    }

    @Override
    public String uploadQuestionImg(MultipartFile file) {
        try {
            // 生成唯一的文件名
            String fileName = CommonUtils.generateUniqueFileName(RandomUtil.randomInt(), file);
            
            // 检查并压缩图片尺寸
            InputStream processedInputStream;
            String contentType = file.getContentType();
            if (isImageFile(file) && needsResize(file)) {
                // 压缩图片到指定尺寸
                processedInputStream = resizeImage(file, 683, 512);
                contentType = "image/jpeg";
            } else {
                // 使用原始文件流
                processedInputStream = file.getInputStream();
            }
            
            // 调用Minio服务上传文件到指定目录
            minioService.upload(MinioConfig.BUCKET,"question", fileName, processedInputStream, contentType);
            // 构造并返回文件访问URL
            return MinioConfig.URL + "/" + MinioConfig.BUCKET + "/question" + fileName;
        } catch (Exception e) {
            log.error("uploadFile 失败, 文件名={}", file.getOriginalFilename(), e);
            throw new FileUploadException(ResultCodeEnum.FILE_UPLOAD_ERROR);
        }
    }

    /**
     * 判断文件是否为图片类型
     * @param file MultipartFile对象
     * @return 是否为图片
     */
    private boolean isImageFile(MultipartFile file) {
        String contentType = file.getContentType();
        return contentType != null && contentType.startsWith("image/");
    }

    /**
     * 判断图片是否需要调整尺寸
     * @param file MultipartFile对象
     * @return 是否需要调整尺寸
     */
    private boolean needsResize(MultipartFile file) {
        try {
            BufferedImage image = ImageIO.read(file.getInputStream());
            return image.getWidth() > 683 || image.getHeight() > 512;
        } catch (Exception e) {
            log.warn("无法读取图片尺寸，跳过尺寸检查: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 调整图片尺寸
     * @param file 原始图片文件
     * @param maxWidth 最大宽度
     * @param maxHeight 最大高度
     * @return 调整尺寸后的图片输入流
     */
    private InputStream resizeImage(MultipartFile file, int maxWidth, int maxHeight) throws IOException {
        try (InputStream inputStream = file.getInputStream()) {
            BufferedImage resizedImage = Thumbnails.of(inputStream)
                    .size(maxWidth, maxHeight)
                    .keepAspectRatio(true)
                    .outputQuality(0.8)
                    .asBufferedImage();
            
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            ImageIO.write(resizedImage, "jpeg", outputStream);
            return new ByteArrayInputStream(outputStream.toByteArray());
        }
    }

    @Override
    public String uploadTextBook(MultipartFile file, String folderName) {
        try {
            // 生成唯一的文件名
            String fileName = CommonUtils.generateUniqueFileName(RandomUtil.randomInt(), file);
            // 调用Minio服务上传文件到指定目录
            minioService.upload(MinioConfig.TEXT_BOOK,folderName, fileName, file.getInputStream(), file.getContentType());
            // 构造并返回文件访问URL
            return MinioConfig.URL + "/" + MinioConfig.TEXT_BOOK + "/" + folderName + fileName;
        } catch (Exception e) {
            log.error("uploadFile 失败, 文件名={}", file.getOriginalFilename(), e);
            throw new FileUploadException(ResultCodeEnum.FILE_UPLOAD_ERROR);
        }
    }

    @Override
    public String uploadTextBook(InputStream inputStream, String fileName, String folderName,String contentType) {
        String originalFilename = CommonUtils.generateUniqueFileName(fileName);
        minioService.upload(MinioConfig.TEXT_BOOK, folderName, originalFilename, inputStream, contentType);
        return MinioConfig.URL + "/" + MinioConfig.TEXT_BOOK +  folderName + "/" + originalFilename;
    }

    @Override
    public String upload(InputStream inputStream,String bucketName, String folderName,String fileName,String contentType) {
        String originalFilename = CommonUtils.generateUniqueFileName(fileName);
        minioService.upload(bucketName, folderName, originalFilename, inputStream, contentType);
        return MinioConfig.URL + "/" + bucketName + "/" + folderName + "/" +  originalFilename;
    }

    @Override
    public String upload(InputStream inputStream, String bucketName, String folderName, String contentType) {
        String originalFilename = CommonUtils.generateUniqueFileName();
        minioService.upload(bucketName, folderName, originalFilename, inputStream, contentType);
        return MinioConfig.URL + "/" + bucketName + "/" + folderName + "/" +  originalFilename;
    }

    /**
     * 从MinIO下载文件
     *
     * @param bucketName 存储桶名称
     * @param objectName 对象名称（包含文件夹路径）
     * @return 文件输入流
     * @throws Exception 可能抛出的异常
     */
    @Override
    public InputStream downloadFile(String bucketName,String objectName) throws Exception {
        return minioService.download(bucketName,objectName);
    }

    @Override
    public InputStream downloadFileFromUrl(String bucketName, String url) throws Exception {
        String objectName = extractObjectNameFromUrl(url, bucketName);
        return downloadFile(bucketName,objectName);
    }

    private String extractObjectNameFromUrl(String fileUrl, String bucketName) {
        try {
            String urlWithoutProtocol = fileUrl.replaceFirst("^https?://", "");

            // 找到第一个斜杠，即服务器地址和路径的分界
            int firstSlashIndex = urlWithoutProtocol.indexOf("/");
            if (firstSlashIndex != -1) {
                // 获取路径部分
                String path = urlWithoutProtocol.substring(firstSlashIndex + 1);
                log.debug("解析URL路径部分: {}", path);

                // 查找BUCKET名称在路径中的位置
                int bucketIndex = path.indexOf(bucketName);
                if (bucketIndex != -1) {
                    // 找到BUCKET后，提取对象名称部分
                    String objectPath = path.substring(bucketIndex + bucketName.length());
                    if (objectPath.startsWith("/")) {
                        objectPath = objectPath.substring(1);
                    }
                    log.debug("通过BUCKET解析出对象路径: {}", objectPath);
                    return objectPath;
                }

                // 如果没有找到BUCKET，尝试直接去掉第一个路径段
                int secondSlashIndex = path.indexOf("/");
                if (secondSlashIndex != -1) {
                    String objectPath = path.substring(secondSlashIndex + 1);
                    log.debug("通过移除第一段路径解析出对象路径: {}", objectPath);
                    return objectPath;
                }
            }
        } catch (Exception e) {
            log.error("解析URL时发生异常: {}", fileUrl, e);
        }

        log.warn("URL格式不符合预期，直接使用原始URL作为对象名称: {}", fileUrl);
        // 如果解析失败，尝试直接使用URL的最后一部分作为对象名称
        String[] parts = fileUrl.split("/");
        if (parts.length > 0) {
            return parts[parts.length - 1];
        }
        throw new IllegalArgumentException("无效的MinIO URL格式: " + fileUrl);
    }
}
