package com.dora.service.impl;

import com.dora.config.OssConfig;
import com.dora.dto.AdminOssUploadRequest;
import com.dora.service.AdminOssService;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.stereotype.Service;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 管理端OSS服务实现类
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class AdminOssServiceImpl implements AdminOssService {

    private final OssConfig ossConfig;

    // 管理员上传文件过期时间，单位为秒（2小时）
    private static final Long ADMIN_EXPIRE_TIME = 7200L;

    @Override
    public Map<String, Object> generateAdminPostSignature(AdminOssUploadRequest request, String adminId) throws Exception {
        String fileName = request.getFileName();
        
        // 验证文件类型
        if (!isAllowedAdminFileType(fileName)) {
            throw new IllegalArgumentException("不支持的文件类型，管理端支持格式：图片、文档、压缩包、音视频等");
        }
        
        // 获取文件大小限制
        long maxFileSize = getMaxAdminFileSize(request.getMaxSizeMB());
        
        String accessKeyId = ossConfig.getAccessKeyId();
        String accessKeySecret = ossConfig.getAccessKeySecret();
        String securityToken = "";

        // 获取x-oss-credential里的date，当前日期，格式为yyyyMMdd
        ZonedDateTime today = ZonedDateTime.now().withZoneSameInstant(ZoneOffset.UTC);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        String date = today.format(formatter);
        
        // 获取x-oss-date
        ZonedDateTime now = ZonedDateTime.now().withZoneSameInstant(ZoneOffset.UTC);
        DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'");
        String x_oss_date = now.format(formatter2);

        // 步骤1：创建policy
        String x_oss_credential = accessKeyId + "/" + date + "/" + ossConfig.getRegion() + "/oss/aliyun_v4_request";

        ObjectMapper mapper = new ObjectMapper();

        Map<String, Object> policy = new HashMap<>();
        policy.put("expiration", generateExpiration(ADMIN_EXPIRE_TIME));

        List<Object> conditions = new ArrayList<>();

        Map<String, String> bucketCondition = new HashMap<>();
        bucketCondition.put("bucket", ossConfig.getBucketName());
        conditions.add(bucketCondition);

        Map<String, String> signatureVersionCondition = new HashMap<>();
        signatureVersionCondition.put("x-oss-signature-version", "OSS4-HMAC-SHA256");
        conditions.add(signatureVersionCondition);

        Map<String, String> credentialCondition = new HashMap<>();
        credentialCondition.put("x-oss-credential", x_oss_credential);
        conditions.add(credentialCondition);

        Map<String, String> dateCondition = new HashMap<>();
        dateCondition.put("x-oss-date", x_oss_date);
        conditions.add(dateCondition);

        // 设置文件大小限制
        conditions.add(Arrays.asList("content-length-range", 1, maxFileSize));
        conditions.add(Arrays.asList("eq", "$success_action_status", "200"));
        
        // 根据文件类型设置Content-Type条件
        String fileExtension = "";
        if (fileName.contains(".")) {
            fileExtension = fileName.substring(fileName.lastIndexOf(".")).toLowerCase();
        }
        
        // 更宽松的Content-Type条件，适合管理端多样化文件类型
        if (fileExtension.matches("\\.(zip|rar|7z|tar|gz|bz2|xz)")) {
            conditions.add(Arrays.asList("starts-with", "$Content-Type", "application/"));
        } else if (fileExtension.matches("\\.(jpg|jpeg|png|gif|bmp|webp|svg)")) {
            conditions.add(Arrays.asList("starts-with", "$Content-Type", "image/"));
        } else if (fileExtension.matches("\\.(mp4|avi|mov|wmv|flv|mkv|webm)")) {
            conditions.add(Arrays.asList("starts-with", "$Content-Type", "video/"));
        } else if (fileExtension.matches("\\.(mp3|wav|flac|aac|ogg|wma)")) {
            conditions.add(Arrays.asList("starts-with", "$Content-Type", "audio/"));
        } else {
            conditions.add(Arrays.asList("starts-with", "$Content-Type", ""));
        }

        policy.put("conditions", conditions);

        String jsonPolicy = mapper.writeValueAsString(policy);

        // 步骤2：构造待签名字符串（StringToSign）
        String stringToSign = new String(Base64.encodeBase64(jsonPolicy.getBytes()));

        // 步骤3：计算SigningKey
        byte[] dateKey = hmacsha256(("aliyun_v4" + accessKeySecret).getBytes(), date);
        byte[] dateRegionKey = hmacsha256(dateKey, ossConfig.getRegion());
        byte[] dateRegionServiceKey = hmacsha256(dateRegionKey, "oss");
        byte[] signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request");

        // 步骤4：计算Signature
        byte[] result = hmacsha256(signingKey, stringToSign);
        String signature = BinaryUtil.toHex(result);

        Map<String, Object> response = new HashMap<>();
        // 后端响应字段名（前端JavaScript使用）
        response.put("policy", stringToSign);
        response.put("x_oss_credential", x_oss_credential);
        response.put("x_oss_date", x_oss_date);
        response.put("version", "OSS4-HMAC-SHA256");  // 前端期望的字段名
        response.put("signature", signature);         // 前端期望的字段名
        response.put("security_token", securityToken);
        
        // 同时提供OSS FormData所需的字段名（用于兼容）
        response.put("x_oss_signature_version", "OSS4-HMAC-SHA256");
        response.put("x_oss_signature", signature);
        
        // 管理端使用专门的目录
        String dir = getAdminUploadDir(request.getDirectory());
        response.put("dir", dir);
        response.put("host", "https://" + ossConfig.getBucketName() + "." + ossConfig.getEndpoint().replace("https://", ""));
        response.put("accessKeyId", accessKeyId);
        response.put("adminId", adminId);
        response.put("fileName", fileName);
        
        // 添加管理端特有的信息
        response.put("fileType", getAdminFileType(fileName));
        response.put("maxFileSize", maxFileSize);
        response.put("maxFileSizeMB", maxFileSize / (1024 * 1024));
        response.put("supportedFormats", getSupportedAdminFormats());
        response.put("uploadTips", getAdminUploadTips(request.getFileCategory()));
        
        log.info("Generated admin POST signature for admin {}: {}, fileType: {}, maxSize: {}MB", 
                adminId, fileName, getAdminFileType(fileName), maxFileSize / (1024 * 1024));
        return response;
    }

    @Override
    public boolean deleteAdminFile(String objectKey, String adminId) throws Exception {
        // 这里可以添加管理员删除文件的逻辑
        // 暂时返回true，实际实现时需要调用OSS SDK
        log.info("Admin {} deleted file: {}", adminId, objectKey);
        return true;
    }

    @Override
    public Map<String, Object> getAdminFileInfo(String objectKey) throws Exception {
        // 这里可以添加获取文件信息的逻辑
        Map<String, Object> fileInfo = new HashMap<>();
        fileInfo.put("objectKey", objectKey);
        fileInfo.put("size", 0L);
        fileInfo.put("lastModified", new Date());
        fileInfo.put("contentType", "application/octet-stream");
        return fileInfo;
    }

    @Override
    public Map<String, Object> batchDeleteAdminFiles(String[] objectKeys, String adminId) throws Exception {
        Map<String, Object> result = new HashMap<>();
        List<String> success = new ArrayList<>();
        List<String> failed = new ArrayList<>();
        
        for (String objectKey : objectKeys) {
            try {
                if (deleteAdminFile(objectKey, adminId)) {
                    success.add(objectKey);
                } else {
                    failed.add(objectKey);
                }
            } catch (Exception e) {
                failed.add(objectKey);
                log.error("Failed to delete file: {}", objectKey, e);
            }
        }
        
        result.put("success", success);
        result.put("failed", failed);
        result.put("total", objectKeys.length);
        result.put("successCount", success.size());
        result.put("failedCount", failed.size());
        
        return result;
    }

    /**
     * 生成过期时间
     */
    private String generateExpiration(long seconds) {
        long now = Instant.now().getEpochSecond();
        long expirationTime = now + seconds;
        Instant instant = Instant.ofEpochSecond(expirationTime);
        ZoneId zone = ZoneOffset.UTC;
        ZonedDateTime zonedDateTime = instant.atZone(zone);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        return zonedDateTime.format(formatter);
    }

    /**
     * 验证管理端允许的文件类型
     */
    private boolean isAllowedAdminFileType(String fileName) {
        if (fileName == null || fileName.isEmpty()) {
            return false;
        }
        
        String extension = "";
        if (fileName.contains(".")) {
            extension = fileName.substring(fileName.lastIndexOf(".")).toLowerCase();
        }
        
        // 管理端支持更多文件格式
        String[] allowedExtensions = {
            // 图片格式
            ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp", ".svg", ".ico", ".tiff",
            // 压缩包格式
            ".zip", ".rar", ".7z", ".tar", ".gz", ".bz2", ".xz",
            // 文档格式
            ".pdf", ".txt", ".md", ".json", ".xml", ".csv", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx",
            // 音频格式
            ".mp3", ".wav", ".flac", ".aac", ".ogg", ".wma",
            // 视频格式
            ".mp4", ".avi", ".mov", ".wmv", ".flv", ".mkv", ".webm",
            // 其他格式
            ".html", ".css", ".js", ".sql", ".log"
        };
        
        for (String allowedExt : allowedExtensions) {
            if (allowedExt.equals(extension)) {
                return true;
            }
        }
        
        return false;
    }

    /**
     * 获取管理端文件大小限制
     */
    private long getMaxAdminFileSize(Integer maxSizeMB) {
        if (maxSizeMB != null && maxSizeMB > 0) {
            // 最大不能超过500MB
            return Math.min(maxSizeMB * 1024L * 1024L, 500L * 1024L * 1024L);
        }
        // 默认50MB
        return 50L * 1024L * 1024L;
    }

    /**
     * 获取管理端上传目录（与用户端使用相同目录）
     */
    private String getAdminUploadDir(String directory) {
        // 使用与用户端相同的目录
        String baseDir = ossConfig.getUserImgFolder();
        if (baseDir.startsWith("/")) {
            baseDir = baseDir.substring(1);
        }
        if (!baseDir.endsWith("/")) {
            baseDir += "/";
        }
        
        // 如果指定了子目录，可以在用户目录下创建子目录
        if (directory != null && !directory.isEmpty()) {
            String subDir = directory;
            if (subDir.startsWith("/")) {
                subDir = subDir.substring(1);
            }
            if (!subDir.endsWith("/")) {
                subDir += "/";
            }
            baseDir += subDir;
        }
        
        return baseDir;
    }

    /**
     * 获取管理端文件类型
     */
    private String getAdminFileType(String fileName) {
        if (fileName == null || fileName.isEmpty()) {
            return "unknown";
        }
        
        String extension = "";
        if (fileName.contains(".")) {
            extension = fileName.substring(fileName.lastIndexOf(".")).toLowerCase();
        }
        
        if (extension.matches("\\.(zip|rar|7z|tar|gz|bz2|xz)")) {
            return "compressed";
        } else if (extension.matches("\\.(jpg|jpeg|png|gif|bmp|webp|svg|ico|tiff)")) {
            return "image";
        } else if (extension.matches("\\.(pdf|txt|md|json|xml|csv|doc|docx|xls|xlsx|ppt|pptx)")) {
            return "document";
        } else if (extension.matches("\\.(mp3|wav|flac|aac|ogg|wma)")) {
            return "audio";
        } else if (extension.matches("\\.(mp4|avi|mov|wmv|flv|mkv|webm)")) {
            return "video";
        } else {
            return "other";
        }
    }

    /**
     * 获取支持的格式列表
     */
    private String[] getSupportedAdminFormats() {
        return new String[]{
            "图片: jpg, jpeg, png, gif, bmp, webp, svg, ico, tiff",
            "文档: pdf, txt, md, json, xml, csv, doc, docx, xls, xlsx, ppt, pptx", 
            "压缩包: zip, rar, 7z, tar, gz, bz2, xz",
            "音频: mp3, wav, flac, aac, ogg, wma",
            "视频: mp4, avi, mov, wmv, flv, mkv, webm",
            "其他: html, css, js, sql, log"
        };
    }

    /**
     * 获取上传提示信息
     */
    private String getAdminUploadTips(String fileCategory) {
        if (fileCategory == null) {
            return "管理端支持多种文件格式，最大支持500MB文件上传。";
        }
        
        switch (fileCategory.toLowerCase()) {
            case "image":
                return "支持常见图片格式，建议使用JPG/PNG格式以获得更好的兼容性。";
            case "document":
                return "支持Office文档和PDF等格式，适合上传说明文档、报告等。";
            case "video":
                return "支持主流视频格式，建议使用MP4格式以获得更好的兼容性。";
            case "audio":
                return "支持多种音频格式，建议使用MP3格式以获得更好的兼容性。";
            case "compressed":
                return "支持常见压缩包格式，适合批量文件上传。";
            default:
                return "管理端支持多种文件格式，请根据实际需要选择合适的文件。";
        }
    }

    /**
     * 计算HMAC-SHA256
     */
    private static byte[] hmacsha256(byte[] key, String data) {
        try {
            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA256");
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(secretKeySpec);
            return mac.doFinal(data.getBytes());
        } catch (Exception e) {
            throw new RuntimeException("Failed to calculate HMAC-SHA256", e);
        }
    }
}
