package com.dora.service.impl;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.vod.model.v20170321.*;
import com.dora.config.VodConfig;
import com.dora.dto.VodDto;
import com.dora.service.VodService;
import com.dora.service.VideoPermissionService;
import com.dora.service.VideoViewStatService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.regex.Pattern;

/**
 * 视频点播服务实现类
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class VodServiceImpl implements VodService {

    private final VodConfig vodConfig;
    private final VideoPermissionService videoPermissionService;
    private final VideoViewStatService videoViewStatService;
    
    // HTML标签匹配的正则表达式
    private static final Pattern HTML_TAG_PATTERN = Pattern.compile("<[^>]*>");

    /**
     * 去除HTML标签并处理长度限制
     * @param originalDescription 原始描述（可能包含HTML标签）
     * @return 处理后的描述，用于发送给阿里云VOD
     */
    private String processDescriptionForVod(String originalDescription) {
        if (originalDescription == null) {
            return null;
        }
        
        // 去除HTML标签
        String plainText = HTML_TAG_PATTERN.matcher(originalDescription).replaceAll("");
        
        // 去除多余的空白字符
        plainText = plainText.replaceAll("\\s+", " ").trim();
        
        // 检查长度限制（阿里云VOD限制为1024字符）
        if (plainText.length() > 1024) {
            plainText = plainText.substring(0, 1021) + "...";
            log.warn("视频描述去除HTML标签后仍然过长，已截断 - 原始长度: {}, HTML去除后长度: {}, 最终长度: {}", 
                    originalDescription.length(), 
                    HTML_TAG_PATTERN.matcher(originalDescription).replaceAll("").replaceAll("\\s+", " ").trim().length(),
                    plainText.length());
        }
        
        return plainText;
    }

    /**
     * 创建VOD客户端
     */
    private DefaultAcsClient createVodClient() throws Exception {
        // 直接使用长期 AK/SK 创建 VOD 客户端（后端直连 OpenAPI，前端拿 UploadAuth）
        IClientProfile profile = DefaultProfile.getProfile(
            vodConfig.getRegion(),
            vodConfig.getAccessKeyId(),
            vodConfig.getAccessKeySecret()
        );
        return new DefaultAcsClient(profile);
    }

    @Override
    public VodDto.UploadAuthResponse getUploadAuth(VodDto.GetUploadAuthRequest request) {
        try {
            DefaultAcsClient client = createVodClient();
            
            CreateUploadVideoRequest vodRequest = new CreateUploadVideoRequest();
            vodRequest.setTitle(request.getTitle());
            
            // 处理描述字段：去除HTML标签并处理长度限制
            // 注意：这里只是处理发送给阿里云的描述，数据库中应保存原始完整内容
            String processedDescription = processDescriptionForVod(request.getDescription());
            vodRequest.setDescription(processedDescription);
            
            vodRequest.setTags(request.getTags());
            if (StringUtils.hasText(request.getCateId())) {
                try {
                    vodRequest.setCateId(Long.valueOf(request.getCateId().trim()));
                } catch (NumberFormatException nfe) {
                    log.warn("无效的cateId(忽略): {}", request.getCateId());
                }
            }
            vodRequest.setCoverURL(request.getCoverUrl());
            vodRequest.setFileName(request.getFileName());
            vodRequest.setFileSize(request.getFileSize());
            // 若配置了存储位置，则强制指定到该存储（例如新加坡的 outin-* bucket）
            if (StringUtils.hasText(vodConfig.getStorageLocation())) {
                vodRequest.setStorageLocation(vodConfig.getStorageLocation().trim());
            }
            
            CreateUploadVideoResponse response = client.getAcsResponse(vodRequest);
            
            VodDto.UploadAuthResponse result = new VodDto.UploadAuthResponse();
            result.setUploadAuth(response.getUploadAuth());
            result.setUploadAddress(response.getUploadAddress());
            result.setVideoId(response.getVideoId());
            result.setRequestId(response.getRequestId());
            
            log.info("获取视频上传凭证成功 - videoId: {}, title: {}, 原始描述长度: {}, 处理后描述长度: {}", 
                    response.getVideoId(), 
                    request.getTitle(),
                    request.getDescription() != null ? request.getDescription().length() : 0,
                    processedDescription != null ? processedDescription.length() : 0);
            return result;
            
        } catch (Exception e) {
            log.error("获取视频上传凭证失败 - title: {}", request.getTitle(), e);
            throw new RuntimeException("获取视频上传凭证失败: " + e.getMessage());
        }
    }

    @Override
    public VodDto.UploadAuthResponse refreshUploadAuth(VodDto.RefreshUploadAuthRequest request) {
        try {
            DefaultAcsClient client = createVodClient();
            
            RefreshUploadVideoRequest vodRequest = new RefreshUploadVideoRequest();
            vodRequest.setVideoId(request.getVideoId());
            
            RefreshUploadVideoResponse response = client.getAcsResponse(vodRequest);
            
            VodDto.UploadAuthResponse result = new VodDto.UploadAuthResponse();
            result.setUploadAuth(response.getUploadAuth());
            result.setUploadAddress(response.getUploadAddress());
            result.setVideoId(response.getVideoId());
            result.setRequestId(response.getRequestId());
            
            log.info("刷新视频上传凭证成功 - videoId: {}", request.getVideoId());
            return result;
            
        } catch (Exception e) {
            log.error("刷新视频上传凭证失败 - videoId: {}", request.getVideoId(), e);
            
            // 特殊处理视频不存在的情况
            if (e.getMessage() != null && e.getMessage().contains("InvalidVideo.NotFound")) {
                throw new RuntimeException("视频不存在，请重新创建上传任务: " + e.getMessage());
            }
            
            throw new RuntimeException("刷新视频上传凭证失败: " + e.getMessage());
        }
    }

    @Override
    public VodDto.PlayAuthResponse getPlayAuth(VodDto.GetPlayAuthRequest request) {
        try {
            DefaultAcsClient client = createVodClient();
            
            GetVideoPlayAuthRequest vodRequest = new GetVideoPlayAuthRequest();
            vodRequest.setVideoId(request.getVideoId());
            vodRequest.setAuthInfoTimeout(request.getAuthInfoTimeout());
            
            GetVideoPlayAuthResponse response = client.getAcsResponse(vodRequest);
            
            VodDto.PlayAuthResponse result = new VodDto.PlayAuthResponse();
            result.setPlayAuth(response.getPlayAuth());
            result.setRequestId(response.getRequestId());
            
            // 设置视频元信息
            VodDto.VideoMeta videoMeta = new VodDto.VideoMeta();
            videoMeta.setVideoId(response.getVideoMeta().getVideoId());
            videoMeta.setTitle(response.getVideoMeta().getTitle());
            videoMeta.setDuration(response.getVideoMeta().getDuration());
            videoMeta.setCoverURL(response.getVideoMeta().getCoverURL());
            videoMeta.setStatus(response.getVideoMeta().getStatus());
            
            result.setVideoMeta(videoMeta);
            
            log.info("获取视频播放凭证成功 - videoId: {}", request.getVideoId());
            return result;
            
        } catch (Exception e) {
            log.error("获取视频播放凭证失败 - videoId: {}", request.getVideoId(), e);
            throw new RuntimeException("获取视频播放凭证失败: " + e.getMessage());
        }
    }

    @Override
    public VodDto.VideoInfoResponse getVideoInfo(VodDto.GetVideoInfoRequest request) {
        try {
            DefaultAcsClient client = createVodClient();
            
            GetVideoInfoRequest vodRequest = new GetVideoInfoRequest();
            vodRequest.setVideoId(request.getVideoId());
            
            GetVideoInfoResponse response = client.getAcsResponse(vodRequest);
            
            VodDto.VideoInfoResponse result = new VodDto.VideoInfoResponse();
            result.setVideoId(response.getVideo().getVideoId());
            result.setTitle(response.getVideo().getTitle());
            result.setDescription(response.getVideo().getDescription());
            result.setDuration(response.getVideo().getDuration());
            result.setCoverURL(response.getVideo().getCoverURL());
            result.setStatus(response.getVideo().getStatus());
            result.setSize(response.getVideo().getSize());
            result.setCreateTime(response.getVideo().getCreateTime());
            result.setModifyTime(response.getVideo().getModifyTime());
            result.setCateId(String.valueOf(response.getVideo().getCateId()));
            result.setCateName(response.getVideo().getCateName());
            result.setTags(response.getVideo().getTags());
            
            log.info("获取视频信息成功 - videoId: {}", request.getVideoId());
            return result;
            
        } catch (Exception e) {
            log.error("获取视频信息失败 - videoId: {}", request.getVideoId(), e);
            throw new RuntimeException("获取视频信息失败: " + e.getMessage());
        }
    }

    @Override
    public VodDto.PlayInfoResponse getPlayInfo(VodDto.GetPlayInfoRequest request, Long userId) {
        // 权限检查
        if (!videoPermissionService.hasVideoAccessPermission(userId, request.getVideoId(), 
                request.getCourseId(), request.getChapterId())) {
            throw new RuntimeException("用户无权限访问该视频");
        }

        try {
            DefaultAcsClient client = createVodClient();
            
            GetPlayInfoRequest vodRequest = new GetPlayInfoRequest();
            vodRequest.setVideoId(request.getVideoId());
            // 注意：阿里云SDK的GetPlayInfoRequest没有setFormat和setDefinition方法
            // 这些参数通过其他方式设置或使用默认值
            
            GetPlayInfoResponse response = client.getAcsResponse(vodRequest);
            
            VodDto.PlayInfoResponse result = new VodDto.PlayInfoResponse();
            result.setVideoId(response.getVideoBase().getVideoId());
            result.setRequestId(response.getRequestId());
            
            // 设置播放地址列表
            VodDto.PlayInfoList playInfoList = new VodDto.PlayInfoList();
            java.util.List<VodDto.PlayInfo> playInfoItems = new java.util.ArrayList<>();
            
            for (GetPlayInfoResponse.PlayInfo playInfo : response.getPlayInfoList()) {
                VodDto.PlayInfo item = new VodDto.PlayInfo();
                item.setPlayURL(playInfo.getPlayURL());
                item.setFormat(playInfo.getFormat());
                item.setDefinition(playInfo.getDefinition());
                item.setDuration(playInfo.getDuration());
                item.setSize(String.valueOf(playInfo.getSize()));
                item.setWidth(String.valueOf(playInfo.getWidth()));
                item.setHeight(String.valueOf(playInfo.getHeight()));
                item.setBitrate(playInfo.getBitrate());
                item.setFps(playInfo.getFps());
                playInfoItems.add(item);
            }
            
            playInfoList.setPlayInfo(playInfoItems);
            result.setPlayInfoList(playInfoList);
            
            log.info("获取视频播放地址成功 - videoId: {}, userId: {}", request.getVideoId(), userId);
            return result;
            
        } catch (Exception e) {
            log.error("获取视频播放地址失败 - videoId: {}, userId: {}", request.getVideoId(), userId, e);
            throw new RuntimeException("获取视频播放地址失败: " + e.getMessage());
        }
    }

    @Override
    public VodDto.VideoPlayAuthResponse getVideoPlayAuth(VodDto.GetVideoPlayAuthRequest request, Long userId) {
        // 权限检查
        if (!videoPermissionService.hasVideoAccessPermission(userId, request.getVideoId(), 
                request.getCourseId(), request.getChapterId())) {
            throw new RuntimeException("用户无权限访问该视频");
        }

        try {
            DefaultAcsClient client = createVodClient();
            
            GetVideoPlayAuthRequest vodRequest = new GetVideoPlayAuthRequest();
            vodRequest.setVideoId(request.getVideoId());
            vodRequest.setAuthInfoTimeout(request.getAuthInfoTimeout());
            // 注意：阿里云SDK的GetVideoPlayAuthRequest没有setPlayDomain方法
            
            GetVideoPlayAuthResponse response = client.getAcsResponse(vodRequest);
            
            VodDto.VideoPlayAuthResponse result = new VodDto.VideoPlayAuthResponse();
            result.setPlayAuth(response.getPlayAuth());
            result.setRequestId(response.getRequestId());
            
            // 设置视频元信息
            VodDto.VideoMeta videoMeta = new VodDto.VideoMeta();
            videoMeta.setVideoId(response.getVideoMeta().getVideoId());
            videoMeta.setTitle(response.getVideoMeta().getTitle());
            // 注意：阿里云SDK的VideoMeta可能没有某些字段，使用安全的方式获取
            videoMeta.setDuration(response.getVideoMeta().getDuration());
            videoMeta.setCoverURL(response.getVideoMeta().getCoverURL());
            videoMeta.setStatus(response.getVideoMeta().getStatus());
            
            result.setVideoMeta(videoMeta);
            
            log.info("获取视频播放凭证成功 - videoId: {}, userId: {}", request.getVideoId(), userId);
            return result;
            
        } catch (Exception e) {
            log.error("获取视频播放凭证失败 - videoId: {}, userId: {}", request.getVideoId(), userId, e);
            throw new RuntimeException("获取视频播放凭证失败: " + e.getMessage());
        }
    }

    @Override
    public VodDto.PlayAuthWithViewCountResponse getPlayAuthWithViewCount(VodDto.GetPlayAuthWithViewCountRequest request, Long userId) {
        try {
            log.info("获取视频播放凭证并增加播放次数 - videoId: {}, userId: {}", request.getVideoId(), userId);
            
            // 1. 获取阿里云播放凭证
            DefaultAcsClient client = createVodClient();
            
            GetVideoPlayAuthRequest vodRequest = new GetVideoPlayAuthRequest();
            vodRequest.setVideoId(request.getVideoId());
            vodRequest.setAuthInfoTimeout(request.getAuthInfoTimeout());
            
            GetVideoPlayAuthResponse response = client.getAcsResponse(vodRequest);
            
            // 2. 记录视频观看并更新播放次数
            VodDto.ViewCountUpdateInfo viewCountInfo = videoViewStatService.recordVideoView(
                request.getVideoId(), 
                userId, 
                request.getCourseId(), 
                request.getChapterId()
            );
            
            // 3. 构建响应
            VodDto.PlayAuthWithViewCountResponse result = new VodDto.PlayAuthWithViewCountResponse();
            result.setPlayAuth(response.getPlayAuth());
            result.setRequestId(response.getRequestId());
            result.setViewCountInfo(viewCountInfo);
            
            // 设置视频元信息
            VodDto.VideoMeta videoMeta = new VodDto.VideoMeta();
            videoMeta.setVideoId(response.getVideoMeta().getVideoId());
            videoMeta.setTitle(response.getVideoMeta().getTitle());
            videoMeta.setDuration(response.getVideoMeta().getDuration());
            videoMeta.setCoverURL(response.getVideoMeta().getCoverURL());
            videoMeta.setStatus(response.getVideoMeta().getStatus());
            
            result.setVideoMeta(videoMeta);
            
            log.info("获取视频播放凭证并增加播放次数成功 - videoId: {}, userId: {}, 播放次数: {} -> {}", 
                    request.getVideoId(), userId, viewCountInfo.getPreviousViewCount(), viewCountInfo.getCurrentViewCount());
            
            return result;
            
        } catch (Exception e) {
            log.error("获取视频播放凭证并增加播放次数失败 - videoId: {}, userId: {}", request.getVideoId(), userId, e);
            throw new RuntimeException("获取视频播放凭证并增加播放次数失败: " + e.toString());
        }
    }
} 