package com.lesingle.creation.common.util;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.PutObjectRequest;
import com.lesingle.creation.common.config.OssProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;

/**
 * 阿里云 OSS 文件上传工具类
 *
 * @author lesingle
 * @since 1.0.0
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class OssUtil {

    private final OssProperties ossProperties;

    /**
     * 允许上传的文件类型
     */
    private static final List<String> ALLOWED_TYPES = Arrays.asList(
        "image/jpeg", "image/png", "image/gif", "image/webp",
        "application/pdf", "application/msword",
        "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
    );

    /**
     * 最大文件大小：100MB
     */
    private static final long MAX_FILE_SIZE = 100 * 1024 * 1024;

    /**
     * 上传文件
     *
     * @param file 上传的文件
     * @return 文件访问 URL
     * @throws IOException 上传失败抛出异常
     */
    public String upload(MultipartFile file) throws IOException {
        // 校验文件
        validateFile(file);

        // 生成文件名
        String fileName = generateFileName(file.getOriginalFilename());

        // 生成文件路径（按日期分目录）
        String objectKey = buildObjectKey(fileName);

        // 获取 OSS 客户端
        OSS ossClient = createOssClient();

        try {
            // 上传文件
            InputStream inputStream = file.getInputStream();
            PutObjectRequest putObjectRequest = new PutObjectRequest(
                ossProperties.getBucketName(),
                objectKey,
                inputStream
            );
            ossClient.putObject(putObjectRequest);

            // 返回文件 URL
            String fileUrl = getFileUrl(objectKey);
            log.info("文件上传成功：{}, URL: {}", objectKey, fileUrl);
            return fileUrl;
        } finally {
            // 关闭客户端
            ossClient.shutdown();
        }
    }

    /**
     * 上传文件（自定义路径）
     *
     * @param file       上传的文件
     * @param customPath 自定义路径（如：avatars/）
     * @return 文件访问 URL
     * @throws IOException 上传失败抛出异常
     */
    public String upload(MultipartFile file, String customPath) throws IOException {
        // 校验文件
        validateFile(file);

        // 生成文件名
        String fileName = generateFileName(file.getOriginalFilename());

        // 生成文件路径
        String objectKey = customPath + (customPath.endsWith("/") ? "" : "/") + fileName;

        // 获取 OSS 客户端
        OSS ossClient = createOssClient();

        try {
            // 上传文件
            InputStream inputStream = file.getInputStream();
            PutObjectRequest putObjectRequest = new PutObjectRequest(
                ossProperties.getBucketName(),
                objectKey,
                inputStream
            );
            ossClient.putObject(putObjectRequest);

            // 返回文件 URL
            String fileUrl = getFileUrl(objectKey);
            log.info("文件上传成功：{}, URL: {}", objectKey, fileUrl);
            return fileUrl;
        } finally {
            // 关闭客户端
            ossClient.shutdown();
        }
    }

    /**
     * 上传字节数组
     *
     * @param bytes     文件字节数组
     * @param fileName  文件名
     * @param customPath 自定义路径
     * @return 文件访问 URL
     * @throws IOException 上传失败抛出异常
     */
    public String upload(byte[] bytes, String fileName, String customPath) throws IOException {
        String finalFileName = generateFileName(fileName);
        String objectKey = customPath + (customPath.endsWith("/") ? "" : "/") + finalFileName;

        OSS ossClient = createOssClient();
        try {
            InputStream inputStream = new ByteArrayInputStream(bytes);
            PutObjectRequest putObjectRequest = new PutObjectRequest(
                ossProperties.getBucketName(),
                objectKey,
                inputStream
            );
            ossClient.putObject(putObjectRequest);

            return getFileUrl(objectKey);
        } finally {
            ossClient.shutdown();
        }
    }

    /**
     * 删除文件
     *
     * @param fileUrl 文件 URL
     */
    public void delete(String fileUrl) {
        String objectKey = extractObjectKey(fileUrl);
        if (objectKey == null) {
            log.warn("无法解析文件 Key: {}", fileUrl);
            return;
        }

        OSS ossClient = createOssClient();
        try {
            ossClient.deleteObject(ossProperties.getBucketName(), objectKey);
            log.info("文件删除成功：{}", objectKey);
        } catch (Exception e) {
            log.error("文件删除失败：{}", objectKey, e);
        } finally {
            ossClient.shutdown();
        }
    }

    /**
     * 校验文件
     */
    private void validateFile(MultipartFile file) {
        // 检查文件是否为空
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("上传文件不能为空");
        }

        // 检查文件大小
        if (file.getSize() > MAX_FILE_SIZE) {
            throw new IllegalArgumentException("文件大小超过限制：" + (MAX_FILE_SIZE / 1024 / 1024) + "MB");
        }

        // 检查文件类型
        String contentType = file.getContentType();
        if (contentType == null || !ALLOWED_TYPES.contains(contentType.toLowerCase())) {
            throw new IllegalArgumentException("不支持的文件类型：" + contentType);
        }
    }

    /**
     * 生成文件名（使用 UUID）
     */
    private String generateFileName(String originalFilename) {
        if (originalFilename == null || originalFilename.isEmpty()) {
            return UUID.randomUUID().toString();
        }

        int dotIndex = originalFilename.lastIndexOf(".");
        if (dotIndex > 0) {
            String extension = originalFilename.substring(dotIndex);
            return UUID.randomUUID().toString() + extension;
        }

        return UUID.randomUUID().toString();
    }

    /**
     * 构建文件路径（按日期分目录）
     */
    private String buildObjectKey(String fileName) {
        String datePath = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd/"));
        String rootDir = ossProperties.getRootDir();

        return (rootDir != null && !rootDir.isEmpty() ? rootDir + "/" : "")
            + datePath + fileName;
    }

    /**
     * 获取文件访问 URL
     */
    private String getFileUrl(String objectKey) {
        if (ossProperties.getCustomDomain() != null && !ossProperties.getCustomDomain().isEmpty()) {
            return ossProperties.getCustomDomain() + "/" + objectKey;
        }

        return "https://" + ossProperties.getBucketName() + "." + ossProperties.getEndpoint() + "/" + objectKey;
    }

    /**
     * 从 URL 中提取 Object Key
     */
    private String extractObjectKey(String fileUrl) {
        if (fileUrl == null || fileUrl.isEmpty()) {
            return null;
        }

        // 尝试从自定义域名解析
        if (ossProperties.getCustomDomain() != null && fileUrl.startsWith(ossProperties.getCustomDomain())) {
            return fileUrl.substring(ossProperties.getCustomDomain().length() + 1);
        }

        // 从 OSS 默认域名解析
        String bucketDomain = ossProperties.getBucketName() + "." + ossProperties.getEndpoint();
        if (fileUrl.contains(bucketDomain)) {
            return fileUrl.substring(fileUrl.indexOf(bucketDomain) + bucketDomain.length() + 1);
        }

        return null;
    }

    /**
     * 创建 OSS 客户端
     */
    private OSS createOssClient() {
        return new OSSClientBuilder().build(
            ossProperties.getEndpoint(),
            ossProperties.getAccessKeyId(),
            ossProperties.getAccessKeySecret()
        );
    }

}
