package cn.reghao.oss.store.task.processor;

import cn.reghao.oss.store.db.repository.ImageRepository;
import cn.reghao.oss.store.model.vo.ObjectProp;
import cn.reghao.oss.store.model.vo.ObjectResult;
import cn.reghao.oss.store.service.FileStoreService;
import cn.reghao.oss.store.service.ObjectNameService;
import cn.reghao.oss.store.service.PutObjectService;
import cn.reghao.jutil.jdk.security.DigestUtil;
import cn.reghao.oss.store.model.po.ImageFile;
import cn.reghao.jutil.media.ImageOps;
import cn.reghao.oss.store.api.constant.SupportedMedia;
import cn.reghao.oss.store.api.rest.UploadFileRet;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * @author reghao
 * @date 2023-06-11 01:29:47
 */
@Slf4j
@Service
public class ImageFileProcessor {
    private final ImageRepository imageRepository;
    private final FileStoreService fileStoreService;
    private final ObjectNameService objectNameService;
    private final PutObjectService putObjectService;

    public ImageFileProcessor(ImageRepository imageRepository, FileStoreService fileStoreService,
                              ObjectNameService objectNameService, PutObjectService putObjectService) {
        this.imageRepository = imageRepository;
        this.fileStoreService = fileStoreService;
        this.objectNameService = objectNameService;
        this.putObjectService = putObjectService;
    }

    public UploadFileRet processImage(ObjectResult objectResult) throws Exception {
        String objectName = objectResult.getObjectName();
        String objectId = objectResult.getObjectId();
        String imageFileId = objectId;
        String objectUrl = objectNameService.getObjectUrl(objectName);
        boolean duplicate = objectResult.isDuplicate();
        if (duplicate) {
            return processDuplicate(objectResult);
        }

        String absolutePath = objectResult.getAbsolutePath();
        File file = new File(absolutePath);
        String format = ImageOps.getFormat(file);
        if (!SupportedMedia.imageFormats.contains(format)) {
            // 在 ChannelValidateService#validateImage 中已做过判断, 理论上不会执行这行代码
            log.error("不支持 {} 图片格式", format);
            return null;
        }

        ImageOps.Size size = ImageOps.info(new File(absolutePath));
        int width = size.getWidth();
        int height = size.getHeight();
        List<ImageFile> list = new ArrayList<>();
        list.add(new ImageFile(imageFileId, objectId, format, objectUrl, width, height));
        if (false) {
            ImageFile imageFile = getConvertedImageFile(objectResult, "webp", width, height);
            list.add(imageFile);
        }

        imageRepository.saveImageFiles(list);
        return new UploadFileRet(objectId, null);
    }

    private UploadFileRet processDuplicate(ObjectResult objectResult) throws Exception {
        String objectName = objectResult.getObjectName();
        String objectId = objectResult.getObjectId();
        String imageFileId = objectId;
        String objectUrl = objectNameService.getObjectUrl(objectName);
        String dupObjectId = objectResult.getDupObjectId();
        List<ImageFile> imageFiles = imageRepository.findImageFiles(dupObjectId);
        ImageFile imageFile = imageFiles.get(0);
        ImageFile imageFile1 = new ImageFile(imageFileId, objectId, objectUrl, imageFile);
        List<ImageFile> list = new ArrayList<>();
        list.add(imageFile1);

        if (false) {
            if (imageFiles.size() > 1) {
                for (int i = 1; i < imageFiles.size(); i++) {
                    ImageFile imageFile2 = imageFiles.get(i);
                    ObjectResult objectResult1 = putObjectService.copyFromObjectId(imageFile2.getObjectId());
                    String objectId1 = objectResult1.getObjectId();
                    String objectUrl1 = objectNameService.getObjectUrl(objectResult1.getObjectName());
                    list.add(new ImageFile(imageFileId, objectId1, objectUrl1, imageFile2));
                }
            } else {
                int width = imageFile.getWidth();
                int height = imageFile.getHeight();
                ImageFile imageFile2 = getConvertedImageFile(objectResult, "webp", width, height);
                list.add(imageFile2);
            }
        }

        imageRepository.saveImageFiles(list);
        return new UploadFileRet(objectId, null);
    }

    private ImageFile getConvertedImageFile(ObjectResult objectResult, String format, int width, int height) throws Exception {
        String imageFileId = objectResult.getObjectId();
        String originalObjectName = objectResult.getObjectName();
        String absolutePath = objectResult.getAbsolutePath();
        File srcFile = new File(absolutePath);
        String contentId = UUID.randomUUID().toString().replace("-", "");
        String destPath = fileStoreService.genFilePath(contentId, srcFile.length(), "."+format);
        File destFile = new File(destPath);

        String srcFormat = ImageOps.getFormat(srcFile);
        if (srcFormat.equals("png")) {
            if ("jpeg".equals(format) || "webp".equals(format)) {
                ImageOps.convertPng(srcFile, destFile, format);
            } else {
                ImageOps.convert2thumbnail(srcFile, destFile, width, height);
            }
        } else {
            if ("jpeg".equals(format)) {
                ImageOps.convert2jpeg(srcFile, destFile);
            } else if ("webp".equals(format)) {
                ImageOps.convert2webp(srcFile, destFile);
            } else {
                ImageOps.convert2thumbnail(srcFile, destFile, width, height);
            }
        }

        if (destFile.exists()) {
            ObjectResult objectResult1 = saveImage(originalObjectName, contentId, "."+format, destFile);
            String objectName1 = objectResult1.getObjectName();
            String objectId1 = objectResult1.getObjectId();
            String objectUrl1 = objectNameService.getObjectUrl(objectName1);
            return new ImageFile(imageFileId, objectId1, format, objectUrl1, width, height);
        } else {
            throw new Exception("image conversion failed");
        }
    }

    private ImageFile getThumbnailFile(ObjectResult objectResult, int width, int height) {
        String imageFileId = objectResult.getObjectId();
        String originalObjectName = objectResult.getObjectName();
        String absolutePath = objectResult.getAbsolutePath();
        File srcFile = new File(absolutePath);

        //int width = 480;
        //int height = 360;
        String format = "jpeg";
        String contentId = UUID.randomUUID().toString().replace("-", "");
        String destPath = fileStoreService.genFilePath(contentId, srcFile.length(), "."+format);
        File destFile = new File(destPath);
        try {
            ImageOps.convert2thumbnail(srcFile, destFile, width, height);
            if (destFile.exists()) {
                ObjectResult objectResult1 = saveImage(originalObjectName, contentId, "."+format, destFile);
                String objectName1 = objectResult1.getObjectName();
                String objectId1 = objectResult1.getObjectId();
                String objectUrl1 = objectNameService.getObjectUrl(objectName1);
                return new ImageFile(imageFileId, objectId1, format, objectUrl1, width, height);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    private ObjectResult saveImage(String originalObjectName, String contentId, String suffix, File savedFile)
            throws Exception {
        ObjectProp objectProp = objectNameService.getObjectProp(originalObjectName, suffix);
        String sha256sum = DigestUtil.sha256sum(savedFile.getAbsolutePath());
        return putObjectService.putObject(objectProp, contentId, savedFile, "", sha256sum);
    }
}
