package cn.iocoder.byzs.module.ai.service.video;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.http.HttpUtil;
import cn.iocoder.byzs.framework.common.pojo.PageResult;
import cn.iocoder.byzs.framework.common.util.object.BeanUtils;
import cn.iocoder.byzs.module.ai.controller.admin.video.vo.AiVideoDrawReqVO;
import cn.iocoder.byzs.module.ai.controller.admin.video.vo.AiVideoPageReqVO;
import cn.iocoder.byzs.module.ai.controller.admin.video.vo.AiVideoPublicPageReqVO;
import cn.iocoder.byzs.module.ai.controller.admin.video.vo.AiVideoUpdateReqVO;
import cn.iocoder.byzs.module.ai.dal.dataobject.model.AiApiKeyDO;
import cn.iocoder.byzs.module.ai.dal.dataobject.model.AiModelDO;
import cn.iocoder.byzs.module.ai.dal.dataobject.video.AiVideoDO;
import cn.iocoder.byzs.module.ai.dal.mysql.video.AiVideoMapper;
import cn.iocoder.byzs.module.ai.enums.video.AiVideoStatusEnum;
import cn.iocoder.byzs.module.ai.service.model.AiApiKeyService;
import cn.iocoder.byzs.module.ai.service.model.AiModelService;
import cn.iocoder.byzs.module.infra.api.file.FileApi;
import com.volcengine.ark.runtime.model.content.generation.CreateContentGenerationTaskRequest;
import com.volcengine.ark.runtime.model.content.generation.CreateContentGenerationTaskRequest.Content;
import com.volcengine.ark.runtime.model.content.generation.CreateContentGenerationTaskResult;
import com.volcengine.ark.runtime.model.content.generation.GetContentGenerationTaskRequest;
import com.volcengine.ark.runtime.model.content.generation.GetContentGenerationTaskResponse;
import com.volcengine.ark.runtime.service.ArkService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import okhttp3.ConnectionPool;
import okhttp3.Dispatcher;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static cn.iocoder.byzs.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.byzs.module.ai.enums.ErrorCodeConstants.VIDEO_NOT_EXISTS;

/**
 * AI 视频 Service 实现类
 *
 * @author fansili
 */
@Service
@Slf4j
public class AiVideoServiceImpl implements AiVideoService {

    @Resource
    private AiModelService modelService;

    @Resource
    private AiVideoMapper videoMapper;

    @Resource
    private FileApi fileApi;
    @Resource
    private AiApiKeyService apiKeyService;

    @Override
    public PageResult<AiVideoDO> getVideoPageMy(Long userId, AiVideoPageReqVO pageReqVO) {
        return videoMapper.selectPageMy(userId, pageReqVO);
    }

    @Override
    public PageResult<AiVideoDO> getVideoPagePublic(AiVideoPublicPageReqVO pageReqVO) {
        return videoMapper.selectPage(pageReqVO);
    }

    @Override
    public AiVideoDO getVideo(Long id) {
        return videoMapper.selectById(id);
    }

    @Override
    public List<AiVideoDO> getVideoList(List<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return videoMapper.selectBatchIds(ids);
    }

    @Override
    public Long drawVideo(Long userId, AiVideoDrawReqVO drawReqVO) {
        // 1. 校验模型
        AiModelDO model = modelService.validateModel(drawReqVO.getModelId());

        // 2. 保存数据库
        String promptImage = null;
        if (CollUtil.isNotEmpty(drawReqVO.getPromptImage())) {
            promptImage = StrUtil.join(",", drawReqVO.getPromptImage());
        }
        AiVideoDO video = BeanUtils.toBean(drawReqVO, AiVideoDO.class).setUserId(userId)
                .setPlatform(model.getPlatform()).setPromptImage(promptImage)
                .setModelId(model.getId()).setModel(model.getModel())
                .setPublicStatus(false).setStatus(AiVideoStatusEnum.IN_PROGRESS.getStatus());
        videoMapper.insert(video);

        // 3. 异步绘制，后续前端通过返回的 id 进行轮询结果
        getSelf().executeDrawVideo(video, drawReqVO, model);
        return video.getId();
    }
    @Async
    @Override
    public void executeDrawVideo(AiVideoDO video, AiVideoDrawReqVO reqVO, AiModelDO model) {
        String filePath = "";

        try {

            AiApiKeyDO apiKeyDo = apiKeyService.validateApiKey(model.getKeyId());
            String apiKey = apiKeyDo.getApiKey();

            ConnectionPool connectionPool = new ConnectionPool(5, 1, TimeUnit.SECONDS);
            Dispatcher dispatcher = new Dispatcher();
            ArkService service = ArkService.builder()
                        .dispatcher(dispatcher)
                        .connectionPool(connectionPool)
                        .apiKey(apiKey)
                        .build();

            List<Content> contents = new ArrayList<>();
            // 图生视频功能
            //文本提示词
            String promptText = reqVO.getPrompt();
            // 第一帧图片
            List<String> promptImage = reqVO.getPromptImage();
            //视频分辨率
            String resolution = reqVO.getResolution();
            //视频时长
            int duration = reqVO.getDuration();
            //是否固定相机位置
            boolean cameraFixed = false;
            //是否添加水印
            boolean watermark = false;

            String formattedPrompt = String.format("%s  --resolution %s  --duration %d --camerafixed %s --watermark %s",
                    promptText, resolution, duration, cameraFixed, watermark);
            contents.add(Content.builder()
                    .type("text")
                    .text(formattedPrompt)
                    .build());

            // 首帧图片
            if (CollUtil.isNotEmpty(promptImage)) {
                promptImage.forEach(url -> {
                    contents.add(Content.builder()
                            .type("image_url")
                            .imageUrl(CreateContentGenerationTaskRequest.ImageUrl.builder()
                                    .url(url) // 请上传可以访问的图片URL
                                    .build())
                            .build());
                });
            }

            // 创建视频生成任务
            CreateContentGenerationTaskRequest createRequest =
                    CreateContentGenerationTaskRequest.builder()
                            .model(model.getModel())
                            .content(contents)
                            .build();

            CreateContentGenerationTaskResult createResult = service.createContentGenerationTask(createRequest);

            // 获取任务详情
            String taskId = createResult.getId();
            GetContentGenerationTaskRequest getRequest = GetContentGenerationTaskRequest.builder()
                    .taskId(taskId)
                    .build();

            Integer videoSstatus = AiVideoStatusEnum.SUCCESS.getStatus();
            // 轮询查询部分
            while (true) {
                try {
                    GetContentGenerationTaskResponse getResponse = service.getContentGenerationTask(getRequest);
                    String status = getResponse.getStatus();
                    if ("succeeded".equalsIgnoreCase(status)) {
                        GetContentGenerationTaskResponse.Content content = getResponse.getContent();

                        System.out.println("---------图片地址：" + content.getVideoUrl());
                        // 下载图片并上传到文件服务
                        byte[] fileContent = HttpUtil.downloadBytes(content.getVideoUrl());
                        filePath = fileApi.createFile(fileContent);
                        break;
                    } else if ("failed".equalsIgnoreCase(status)) {
                        filePath = "http://errr.png";
                        videoSstatus = AiVideoStatusEnum.FAIL.getStatus();
                        break;
                    } else {
                        TimeUnit.SECONDS.sleep(3);
                        log.info("[executeDrawVideo][video({}) 定时生成查询, 状态({})]", video, getResponse);
                    }
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }

            // 3. 更新数据库
            videoMapper.updateById(new AiVideoDO().setId(video.getId()).setStatus(videoSstatus)
                    .setVideoUrl(filePath).setFinishTime(LocalDateTime.now()));

            // shutdown service after all requests is finished
            service.shutdownExecutor();

        } catch (Exception ex) {
            log.error("[executeDrawVideo][video({}) 生成异常]", video, ex);
            videoMapper.updateById(new AiVideoDO().setId(video.getId())
                    .setStatus(AiVideoStatusEnum.FAIL.getStatus())
                    .setErrorMessage(ex.getMessage()).setFinishTime(LocalDateTime.now()));
        }
    }

    @Override
    public void deleteVideoMy(Long id, Long userId) {
        // 1. 校验是否存在
        AiVideoDO video = validateVideoExists(id);
        if (ObjUtil.notEqual(video.getUserId(), userId)) {
            throw exception(VIDEO_NOT_EXISTS);
        }
        // 2. 删除记录
        videoMapper.deleteById(id);
    }

    @Override
    public PageResult<AiVideoDO> getVideoPage(AiVideoPageReqVO pageReqVO) {
        return videoMapper.selectPage(pageReqVO);
    }

    @Override
    public void updateVideo(AiVideoUpdateReqVO updateReqVO) {
        // 1. 校验存在
        validateVideoExists(updateReqVO.getId());
        // 2. 更新发布状态
        videoMapper.updateById(BeanUtils.toBean(updateReqVO, AiVideoDO.class));
    }

    @Override
    public void deleteVideo(Long id) {
        // 1. 校验存在
        validateVideoExists(id);
        // 2. 删除
        videoMapper.deleteById(id);
    }

    private AiVideoDO validateVideoExists(Long id) {
        AiVideoDO video = videoMapper.selectById(id);
        if (video == null) {
            throw exception(VIDEO_NOT_EXISTS);
        }
        return video;
    }


    /**
     * 获得自身的代理对象，解决 AOP 生效问题
     *
     * @return 自己
     */
    private AiVideoService getSelf() {
        return SpringUtil.getBean(AiVideoService.class);
    }
}