package com.moka.gdtauto.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.moka.gdtauto.client.TencentAdsApiClientFactory;
import com.moka.gdtauto.entity.TencentAssetDrama;
import com.moka.gdtauto.entity.TencentVideo;
import com.moka.gdtauto.mapper.TencentVideoMapper;
import com.moka.gdtauto.service.TencentAssetDramaService;
import com.moka.gdtauto.service.TencentVideoService;
import com.moka.gdtauto.util.VideoWatermarkUtil;
import com.tencent.ads.model.v3.VideosAddResponseData;
import com.tencent.ads.v3.TencentAds;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.math.BigInteger;
import java.nio.file.Files;
import java.security.MessageDigest;
import java.time.LocalDateTime;

/**
 * 腾讯广告视频Service实现类
 *
 * @author moka
 * @since 2026-02-06
 */
@Slf4j
@Service
public class TencentVideoServiceImpl extends ServiceImpl<TencentVideoMapper, TencentVideo>
        implements TencentVideoService {

    @Autowired
    private TencentAdsApiClientFactory clientFactory;

    @Autowired
    private TencentAssetDramaService dramaService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public TencentVideo uploadVideo(String jobNumber,  Long accountId, MultipartFile file, 
                                    Boolean hasWatermark, Long dramaId,
                                    Integer watermarkDuration, String description) {
        TencentVideo videoRecord = new TencentVideo();
        videoRecord.setAccountId(accountId);
        videoRecord.setOriginalFilename(file.getOriginalFilename());
        videoRecord.setHasWatermark(hasWatermark != null && hasWatermark);
        videoRecord.setDramaId(dramaId);
        videoRecord.setWatermarkDuration(watermarkDuration);
        videoRecord.setDescription(description);
        videoRecord.setCreatedTime(LocalDateTime.now());
        videoRecord.setUpdatedTime(LocalDateTime.now());

        File tempFile = null;
        File watermarkedFile = null;

        try {
            // 1. 保存临时文件
            // 加个随机数，避免文件名冲突
            String randomSuffix = String.valueOf(System.currentTimeMillis());
            tempFile = File.createTempFile("upload-video-" + randomSuffix + "-", getFileExtension(file.getOriginalFilename()));
            file.transferTo(tempFile);
            log.info("临时视频文件保存成功: {}", tempFile.getAbsolutePath());

            // 获取视频时长
            Integer videoDuration = getVideoDuration(tempFile);
            if (videoDuration != null) {
                videoRecord.setVideoDuration(videoDuration);
                log.info("视频时长: {} 秒", videoDuration);
            }

            File fileToUpload = tempFile;

            // 2. 如果需要添加水印
            if (hasWatermark != null && hasWatermark && dramaId != null) {
                TencentAssetDrama drama = dramaService.getById(dramaId);
                if (drama != null && drama.getMarketingAssetName() != null) {
                    log.info("开始添加水印，剧名: {}, 水印时长: {} 秒", 
                        drama.getMarketingAssetName(), 
                        watermarkDuration == null ? "全程" : watermarkDuration);

                    // 创建水印文件
                    watermarkedFile = File.createTempFile("watermarked-video-", ".mp4");

                    // 添加水印到左上角
                    VideoWatermarkUtil.addWatermark(
                            tempFile.getAbsolutePath(),
                            watermarkedFile.getAbsolutePath(),
                            drama.getMarketingAssetName(),
                            watermarkDuration  // null表示全程，否则为指定秒数
                    );

                    fileToUpload = watermarkedFile;
                    videoRecord.setWatermarkText(drama.getMarketingAssetName());
                    log.info("水印添加成功: {}", drama.getMarketingAssetName());
                }
            }

            // 3. 计算MD5签名
            String signature = calculateMD5(fileToUpload);
            log.info("视频MD5签名: {}", signature);

            // 4. 获取TencentAds客户端
            TencentAds tencentAds = clientFactory.getTencentAdsWithoutUserToken(jobNumber, accountId);
            log.info("开始上传视频到腾讯广告，账户ID: {}", accountId);

            // 5. 调用腾讯广告API上传视频
            VideosAddResponseData response = tencentAds.videos()
                    .videosAdd(
                            fileToUpload,
                            signature,
                            accountId,
                            null,
                            description,
                            null
                    );

            // 6. 保存上传结果
            if (response != null) {
                videoRecord.setVideoId(response.getVideoId() != null ? response.getVideoId().toString() : null);
                videoRecord.setCoverImageId(response.getCoverImageId() != null ? response.getCoverImageId().toString() : null);
                videoRecord.setUploadStatus("SUCCESS");

                log.info("视频上传成功 - 视频ID: {}, 封面图片ID: {}",
                        response.getVideoId(),
                        response.getCoverImageId());
            } else {
                videoRecord.setUploadStatus("FAILED");
                videoRecord.setErrorMessage("上传返回结果为空");
                log.error("视频上传失败: 返回结果为空");
            }

        } catch (Exception e) {
            log.error("视频上传失败", e);
            videoRecord.setUploadStatus("FAILED");
            videoRecord.setErrorMessage(e.getMessage());
        } finally {
            // 清理临时文件
            if (tempFile != null && tempFile.exists()) {
                try {
                    Files.delete(tempFile.toPath());
                    log.debug("临时文件删除成功: {}", tempFile.getAbsolutePath());
                } catch (Exception e) {
                    log.warn("临时文件删除失败: {}", tempFile.getAbsolutePath(), e);
                }
            }
            if (watermarkedFile != null && watermarkedFile.exists()) {
                try {
                    Files.delete(watermarkedFile.toPath());
                    log.debug("水印文件删除成功: {}", watermarkedFile.getAbsolutePath());
                } catch (Exception e) {
                    log.warn("水印文件删除失败: {}", watermarkedFile.getAbsolutePath(), e);
                }
            }
        }

        // 7. 保存记录到数据库
        this.save(videoRecord);
        log.info("视频记录保存成功，ID: {}", videoRecord.getId());

        return videoRecord;
    }

    /**
     * 获取视频时长（秒）
     */
    private Integer getVideoDuration(File videoFile) {
        FFmpegFrameGrabber grabber = null;
        try {
            grabber = new FFmpegFrameGrabber(videoFile);
            grabber.start();
            long lengthInMicroseconds = grabber.getLengthInTime();
            int durationInSeconds = (int) (lengthInMicroseconds / 1000000);
            return durationInSeconds;
        } catch (Exception e) {
            log.warn("获取视频时长失败", e);
            return null;
        } finally {
            if (grabber != null) {
                try {
                    grabber.stop();
                    grabber.release();
                } catch (Exception e) {
                    // ignore
                }
            }
        }
    }

    /**
     * 计算文件的MD5签名
     */
    private String calculateMD5(File file) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        try (FileInputStream fis = new FileInputStream(file)) {
            byte[] buffer = new byte[8192];
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                md.update(buffer, 0, bytesRead);
            }
        }
        byte[] digest = md.digest();
        BigInteger bigInt = new BigInteger(1, digest);
        String hashtext = bigInt.toString(16);
        // 补齐前导0
        while (hashtext.length() < 32) {
            hashtext = "0" + hashtext;
        }
        return hashtext;
    }

    /**
     * 获取文件扩展名
     */
    private String getFileExtension(String filename) {
        if (filename == null || !filename.contains(".")) {
            return ".mp4";
        }
        return filename.substring(filename.lastIndexOf("."));
    }
}
