package edu.whut.smilepicturebackend.manager;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.model.*;
import com.qcloud.cos.model.ciModel.persistence.PicOperations;
import com.qcloud.cos.utils.IOUtils;
import edu.whut.smilepicturebackend.config.CosClientConfig;
import edu.whut.smilepicturebackend.exception.BusinessException;
import edu.whut.smilepicturebackend.exception.ErrorCode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;


/**
 * 和业务没有关系，通用的文件上传下载
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class CosManager {

    private final CosClientConfig cosClientConfig;

    private final COSClient cosClient;

    final long THUMBNAIL_THRESHOLD = 20 * 1024;  // 20 KB

    /**
     * 上传对象
     *
     * @param key  唯一键 ，相当于桶内的「文件路径」！
     * @param file 文件
     */
    public PutObjectResult putObject(String key, File file) {
        PutObjectRequest putObjectRequest = new PutObjectRequest(cosClientConfig.getBucket(), key,
                file);
        return cosClient.putObject(putObjectRequest);
    }

    /**
     * 上传对象（附带图片信息）
     *
     * @param key  唯一键
     * @param file 文件
     */
    public PutObjectResult putPictureObject(String key, File file) {
        PutObjectRequest putObjectRequest = new PutObjectRequest(cosClientConfig.getBucket(), key,
                file);
        // 对图片进行处理（获取基本信息也被视作为一种图片的处理）
        PicOperations picOperations = new PicOperations();
        // 1 表示返回原图信息
        picOperations.setIsPicInfo(1);
        // 图片处理规则列表
        List<PicOperations.Rule> rules = new ArrayList<>();
        // 1. 图片压缩（转成 webp 格式） https://cloud.tencent.com/document/product/436/42215
        String webpKey = FileUtil.mainName(key) + ".webp";
        PicOperations.Rule compressRule = new PicOperations.Rule();
        compressRule.setFileId(webpKey);
        compressRule.setBucket(cosClientConfig.getBucket());
        compressRule.setRule("imageMogr2/format/webp");
        rules.add(compressRule);
        // 2. 缩略图处理，仅对 > 20 KB 的图片生成缩略图  https://cloud.tencent.com/document/product/436/113295
        if (file.length() > THUMBNAIL_THRESHOLD) {
            PicOperations.Rule thumbnailRule = new PicOperations.Rule();
            // 拼接缩略图的路径
            String thumbnailKey = FileUtil.mainName(key) + "_thumbnail." + FileUtil.getSuffix(key);
            thumbnailRule.setFileId(thumbnailKey);
            thumbnailRule.setBucket(cosClientConfig.getBucket());
            // 缩放规则 /thumbnail/<Width>x<Height>>（如果大于原图宽高，则不处理）
            thumbnailRule.setRule(String.format("imageMogr2/thumbnail/%sx%s>", 400, 400));
            rules.add(thumbnailRule);
        }
        // 构造处理参数
        picOperations.setRules(rules);
        putObjectRequest.setPicOperations(picOperations);
        return cosClient.putObject(putObjectRequest);
    }


    /**
     * 上传对象，接收InputStream文件流
     * @param key
     * @param in
     * @param contentLength
     * @param contentType
     */
    public PutObjectResult putObjectStream(String key,
                                           InputStream in,
                                           long contentLength,
                                           String contentType) {
        // 1. 构建 metadata
        ObjectMetadata meta = new ObjectMetadata();
        meta.setContentLength(contentLength);
        meta.setContentType(contentType);
        // （如果有额外的 metadata，比如缓存控制、Content-Disposition 等，也一并在这里设置）

        // 2. 构造 PutObjectRequest —— 支持 InputStream + metadata
        PutObjectRequest request = new PutObjectRequest(
                cosClientConfig.getBucket(),
                key,
                in,
                meta
        );

        // 3. 调用同一个接口上传
        return cosClient.putObject(request);
    }
    /**
     * 上传对象，接收InputStream文件流,附带图片信息
     * @param key
     * @param in
     * @param contentLength
     * @param contentType
     */
    public PutObjectResult putPictureObjectStream(
            String key,
            InputStream in,
            long contentLength,
            String contentType) {

        // 1. 构建基本的元数据
        ObjectMetadata meta = new ObjectMetadata();
        meta.setContentLength(contentLength);
        meta.setContentType(contentType);

        // 2. 构造带流的上传请求
        //    这里使用了流式的 PutObjectRequest 构造器
        PutObjectRequest request = new PutObjectRequest(
                cosClientConfig.getBucket(),
                key,
                in,
                meta
        );

        // 3. 设置图片处理操作：返回原图信息
        PicOperations picOps = new PicOperations();
        picOps.setIsPicInfo(1);
        request.setPicOperations(picOps);

        // 4. 执行上传
        return cosClient.putObject(request);
    }

    /**
     * 下载对象
     *
     * @param key 唯一键
     */
    public COSObject getObject(String key) {
        GetObjectRequest getObjectRequest = new GetObjectRequest(cosClientConfig.getBucket(), key);
        return cosClient.getObject(getObjectRequest);
    }


    /**
     * 删除对象 https://cloud.tencent.com/document/product/436/65939
     * @param url
     */
    public void deleteIfNotBlank(String url) {
        if (StrUtil.isBlank(url)) {
            return;
        }
        try {
            // 1. 解析 URL → 得到对象 key
            String key = extractUploadPath(url);
            if (StrUtil.isBlank(key)) {
                log.warn("无法从 URL 解析出 COS 对象 key，跳过删除: {}", url);
                return;
            }
            // 2. 调用 COS SDK 删除
            log.info("清理图片中... {}", key);
            cosClient.deleteObject(cosClientConfig.getBucket(), key);
        } catch (IllegalArgumentException e) {
            // URL 格式非法或解析失败时给出警告，不中断业务
            log.warn("删除图片失败：URL 解析异常，url={}", url, e);
        }
    }

    /**
     *  从完整 COS URL 中解析出对象 key（即 uploadPath）
     *
     *  @param originalUrl  形如 https://bucket.cos.xxx/my/prefix/file.png
     *  @return             my/prefix/file.png
     */
    public String extractUploadPath(String originalUrl) {
        try {
            // 1. 直接拿 URI 的 path 部分，例如  "//smile-picture/public/.../xxx.png"
            String path = new URI(originalUrl).getPath();

            // 2. 去掉所有前导斜杠，得到真正的 COS 对象 key
            return path.replaceFirst("^/+", "");   // => smile-picture/public/.../xxx.png
        } catch (URISyntaxException e) {
            throw new IllegalArgumentException("非法的 COS URL: " + originalUrl, e);
        }
    }

    /**
     * 将COS中的文件下载到本地
     * @param filepath  文件路径，如folder/picture.jpg
     * @param localPath 本地存储路径
     */
    public void downloadPicture(String filepath, String localPath) throws IOException {
        File file = new File(localPath);
        COSObjectInputStream cosObjectInput = null;
        try {
            COSObject cosObject = this.getObject(filepath);
            cosObjectInput = cosObject.getObjectContent();
            // 将输入流转为字节数组
            byte[] data = IOUtils.toByteArray(cosObjectInput);
            // 将字节数组写入本地文件
            FileUtil.writeBytes(data, file);
        } catch (Exception e) {
            log.error("file download error, filepath = {}", filepath, e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "下载失败");
        } finally {
            if (cosObjectInput != null) {
                cosObjectInput.close();
            }
        }
    }

}
