package com.ycwl.basic.service.task.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ycwl.basic.biz.OrderBiz;
import com.ycwl.basic.biz.TaskStatusBiz;
import com.ycwl.basic.biz.TemplateBiz;
import com.ycwl.basic.constant.StorageConstant;
import com.ycwl.basic.constant.TaskConstant;
import com.ycwl.basic.mapper.FaceMapper;
import com.ycwl.basic.mapper.FaceSampleMapper;
import com.ycwl.basic.mapper.MemberMapper;
import com.ycwl.basic.mapper.RenderWorkerMapper;
import com.ycwl.basic.mapper.SourceMapper;
import com.ycwl.basic.mapper.TaskMapper;
import com.ycwl.basic.mapper.TemplateMapper;
import com.ycwl.basic.mapper.VideoMapper;
import com.ycwl.basic.model.mobile.order.IsBuyRespVO;
import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
import com.ycwl.basic.model.pc.member.resp.MemberRespVO;
import com.ycwl.basic.model.pc.mp.MpConfigEntity;
import com.ycwl.basic.model.pc.renderWorker.entity.RenderWorkerEntity;
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
import com.ycwl.basic.model.pc.scenic.entity.ScenicEntity;
import com.ycwl.basic.model.pc.source.entity.SourceEntity;
import com.ycwl.basic.model.pc.task.entity.TaskEntity;
import com.ycwl.basic.model.pc.task.req.TaskReqQuery;
import com.ycwl.basic.model.pc.task.resp.TaskRespVO;
import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
import com.ycwl.basic.model.pc.video.entity.MemberVideoEntity;
import com.ycwl.basic.model.pc.video.entity.VideoEntity;
import com.ycwl.basic.model.task.req.ClientStatusReqVo;
import com.ycwl.basic.model.task.req.TaskReqVo;
import com.ycwl.basic.model.task.req.TaskSuccessReqVo;
import com.ycwl.basic.model.task.req.WorkerAuthReqVo;
import com.ycwl.basic.model.task.resp.TaskSyncRespVo;
import com.ycwl.basic.notify.NotifyFactory;
import com.ycwl.basic.notify.adapters.INotifyAdapter;
import com.ycwl.basic.notify.entity.NotifyContent;
import com.ycwl.basic.notify.enums.NotifyType;
import com.ycwl.basic.repository.DeviceRepository;
import com.ycwl.basic.repository.FaceRepository;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.repository.VideoRepository;
import com.ycwl.basic.repository.VideoTaskRepository;
import com.ycwl.basic.service.pc.ScenicService;
import com.ycwl.basic.service.task.TaskService;
import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.enums.StorageAcl;
import com.ycwl.basic.storage.utils.StorageUtil;
import com.ycwl.basic.task.VideoPieceGetter;
import com.ycwl.basic.repository.TemplateRepository;
import com.ycwl.basic.utils.SnowFlakeUtil;
import com.ycwl.basic.utils.VideoReUploader;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

@Slf4j
@Service
public class TaskTaskServiceImpl implements TaskService {
    @Autowired
    private TemplateMapper templateMapper;
    @Autowired
    private RenderWorkerMapper renderWorkerMapper;
    @Autowired
    private TaskMapper taskMapper;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private FaceMapper faceMapper;
    @Autowired
    private FaceSampleMapper faceSampleMapper;
    @Autowired
    private SourceMapper sourceMapper;
    @Autowired
    private VideoMapper videoMapper;
    @Autowired
    private TemplateRepository templateRepository;
    @Autowired
    private VideoTaskRepository videoTaskRepository;
    @Autowired
    private OrderBiz orderBiz;
    @Autowired
    private MemberMapper memberMapper;
    @Autowired
    private ScenicRepository scenicRepository;
    @Autowired
    private TemplateBiz templateBiz;
    @Autowired
    private FaceRepository faceRepository;
    @Autowired
    private VideoRepository videoRepository;
    @Autowired
    private ScenicService scenicService;

    private final ReentrantLock lock = new ReentrantLock();
    @Autowired
    private TaskStatusBiz taskStatusBiz;
    @Autowired
    private DeviceRepository deviceRepository;
    @Autowired
    private VideoReUploader videoReUploader;


    private RenderWorkerEntity getWorker(@NonNull WorkerAuthReqVo req) {
        String accessKey = req.getAccessKey();
        if (accessKey == null) {
            return null;
        }
        return renderWorkerMapper.findByAccessKey(accessKey);
    }

    @Override
    public TaskSyncRespVo handleSyncTask(@NonNull TaskReqVo req) {
        RenderWorkerEntity worker = getWorker(req);
        if (worker == null) {
            return null;
        }
        worker.setOnline(1);
        worker.setName(null);
        worker.setStatus(null);
        // get status
        ClientStatusReqVo clientStatus = req.getClientStatus();
        if (clientStatus != null) {
            // 临时这么用下
            worker.setCpuCount(clientStatus.getCpu_count());
            worker.setCpuUsage(clientStatus.getCpu_usage());
            // 上报的是字节，存储的是兆
            worker.setMemoryAvailable(clientStatus.getMemory_available().divide(BigDecimal.valueOf(1024 * 1024), RoundingMode.CEILING));
            worker.setMemoryTotal(clientStatus.getMemory_total().divide(BigDecimal.valueOf(1024 * 1024), RoundingMode.CEILING));

            worker.setPlatform(clientStatus.getPlatform());
            worker.setRuntimeVersion(clientStatus.getRuntime_version());
            worker.setSupportFeature(String.join(",", clientStatus.getSupport_feature()));
            worker.setVersion(clientStatus.getVersion());

            worker.setUpdateAt(new Date());
            redisTemplate.opsForValue().set(TaskConstant.TASK_ONLINE_WORKER_KEY_PFX + worker.getId(), JSON.toJSONString(clientStatus), 60, TimeUnit.SECONDS);
        }
        renderWorkerMapper.update(worker);
        TaskSyncRespVo resp = new TaskSyncRespVo();
        // Template
        List<TemplateRespVO> updTemplateList;
        if (req.getTemplateList() != null) {
            updTemplateList = new ArrayList<>();
            // 上报了本地模板列表
            req.getTemplateList().forEach(template -> {
                if (StringUtils.isNumeric(template.getId())) {
                    TemplateRespVO dbTemplate = templateRepository.getTemplate(Long.parseLong(template.getId()));
                    if (dbTemplate == null) {
                        return;
                    }
                    if (!dbTemplate.getUpdateTime().equals(template.getUpdateTime())) {
                        updTemplateList.add(dbTemplate);
                    }
                }
            });
        } else {
            updTemplateList = templateRepository.getAllEnabledTemplateList();
        }
        try {
            if (lock.tryLock(2, TimeUnit.SECONDS)) {
                try {
                    List<TaskRespVO> taskList;
                    if (worker.getScenicOnly() != null) {
                        taskList = taskMapper.selectNotRunningByScenicList(worker.getScenicOnly());
                    } else {
                        taskList = taskMapper.selectNotRunning();
                    }
                    resp.setTasks(taskList);
                    resp.setTemplates(updTemplateList);
                    taskList.forEach(task -> {
                        taskMapper.assignToWorker(task.getId(), worker.getId());
                        videoTaskRepository.clearTaskCache(task.getId());
                    });
                } finally {
                    lock.unlock();
                }
            }
        } catch (InterruptedException ignored) {
        }
        // return Task
        return resp;
    }

    @Override
    public TemplateRespVO workerGetTemplate(@NonNull Long templateId, @NonNull WorkerAuthReqVo req) {
        RenderWorkerEntity worker = getWorker(req);
        if (worker == null) {
            return null;
        }
        return templateRepository.getTemplate(templateId);
    }

    @Override
    public void taskStart(@NonNull Long taskId, @NonNull WorkerAuthReqVo req) {
        TaskRespVO task = taskMapper.getById(taskId);
        if (task == null) {
            return;
        }
        RenderWorkerEntity worker = getWorker(req);
        if (worker == null) {
            return;
        }
        TaskEntity taskUpdate = new TaskEntity();
        taskUpdate.setId(taskId);
        taskUpdate.setWorkerId(worker.getId());
        taskMapper.setStart(taskUpdate);
        videoTaskRepository.clearTaskCache(taskUpdate.getId());
    }

    @Override
    public void forceCreateTaskByFaceIdAndTempalteId(Long faceId, Long templateId) {
        FaceEntity face = faceRepository.getFace(faceId);
        if (face == null) {
            log.info("faceId:{} is not exist", faceId);
            return;
        }
        List<FaceSampleEntity> faceSampleList = faceRepository.getFaceSampleList(faceId);
        if (faceSampleList.isEmpty()) {
            log.info("faceId:{} sample list not exist", faceId);
        }
        List<Long> faceSampleIds = faceSampleList.stream().map(FaceSampleEntity::getId).collect(Collectors.toList());
        List<SourceEntity> sourceList = sourceMapper.listVideoByScenicFaceRelation(face.getScenicId(), faceId);
        VideoPieceGetter.Task task = new VideoPieceGetter.Task();
        task.faceId = faceId;
        task.faceSampleIds = faceSampleIds;
        task.templateId = templateId;
        task.memberId = face.getMemberId();
        task.callback = () -> {
            log.info("task callback");
            List<SourceEntity> videoSourceList = sourceMapper.listVideoByScenicFaceRelation(face.getScenicId(), faceId);
            Map<String, List<SourceEntity>> sourcesMap = videoSourceList.stream()
                    .peek(item -> item.setUrl(item.getVideoUrl()))
                    .filter(item -> {
                        DeviceEntity device = deviceRepository.getDevice(item.getDeviceId());
                        return Integer.valueOf(1).equals(device.getStatus());
                    })
                    .filter(item -> item.getDeviceId() != null) // 添加对 deviceId 为 null 的检查
                    .collect(Collectors.groupingBy(item -> item.getDeviceId().toString()));
            if (sourcesMap.isEmpty()) {
                // 主动禁止没有视频源视频生成
                log.info("task callback: 没有视频源");
                return;
            }
            List<String> templatePlaceholder = templateRepository.getTemplatePlaceholder(templateId);
            if (templatePlaceholder.stream().distinct().count() == templatePlaceholder.size()) {
                sourcesMap.forEach((key, value) -> {
                    // 每个value只保留第一个
                    value.removeIf(item -> !value.getFirst().equals(item));
                });
            } else {
                log.info("task callback: 模板占位符有重复，templateId: {}", templateId);
            }
            TaskReqQuery taskReqQuery = new TaskReqQuery();
            taskReqQuery.setFaceId(faceId);
            taskReqQuery.setTemplateId(templateId);
            taskReqQuery.setTaskParams(JSON.toJSONString(sourcesMap));
            List<TaskRespVO> list = taskMapper.list(taskReqQuery);

            MemberVideoEntity memberVideoEntity = new MemberVideoEntity();
            memberVideoEntity.setMemberId(face.getMemberId());
            memberVideoEntity.setScenicId(face.getScenicId());
            memberVideoEntity.setFaceId(faceId);
            memberVideoEntity.setTemplateId(templateId);
            memberVideoEntity.setIsBuy(0);
            if (list.isEmpty()) {
                log.info("创建任务! faceId:{},templateId:{},taskParams:{}", faceId, templateId, sourcesMap);
                ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(face.getScenicId());
                TaskEntity taskEntity = null;
                if (Integer.valueOf(0).equals(scenicConfig.getTemplateNewVideoType())) {
                    log.info("景区{}启用：templateNewVideoType：全新视频原位替换", face.getScenicId());
                    taskReqQuery.setTemplateId(templateId);
                    List<TaskEntity> templateTaskList = taskMapper.listEntity(taskReqQuery);
                    if (!templateTaskList.isEmpty()) {
                        taskEntity = templateTaskList.getFirst();
                        log.info("已有旧生成的视频：{}", taskEntity);
                        MemberVideoEntity taskVideoRelation = videoMapper.queryRelationByMemberTask(face.getMemberId(), taskEntity.getId());
                        if (taskVideoRelation != null) {
                            log.info("已有旧关联记录的视频：{}", taskVideoRelation);
                            memberVideoEntity.setIsBuy(taskVideoRelation.getIsBuy());
                            memberVideoEntity.setOrderId(taskVideoRelation.getOrderId());
                        }
                        taskMapper.deleteById(taskEntity.getId());
                    }
                }
                if (taskEntity == null) {
                    taskEntity = new TaskEntity();
                    taskEntity.setId(SnowFlakeUtil.getLongId());
                    taskEntity.setScenicId(face.getScenicId());
                    taskEntity.setFaceId(faceId);
                    taskEntity.setTemplateId(templateId);
                    taskEntity.setAutomatic(0);
                }
                taskEntity.setWorkerId(null);
                taskEntity.setStatus(0);
                taskEntity.setTaskParams(JSON.toJSONString(sourcesMap));
                taskMapper.add(taskEntity);
                memberVideoEntity.setTaskId(taskEntity.getId());
            } else {
                log.info("重复task! faceId:{},templateId:{},taskParams:{}", faceId, templateId, sourcesMap);
                memberVideoEntity.setTaskId(list.getFirst().getId());
                VideoEntity video = videoMapper.findByTaskId(list.getFirst().getId());
                if (video != null) {
                    IsBuyRespVO isBuy = orderBiz.isBuy(face.getMemberId(), list.getFirst().getScenicId(), 0, video.getId());
                    if (isBuy.isBuy()) {
                        memberVideoEntity.setIsBuy(1);
                        memberVideoEntity.setOrderId(isBuy.getOrderId());
                    }
                    if (isBuy.isFree()) {
                        memberVideoEntity.setIsBuy(1);
                    }
                    memberVideoEntity.setVideoId(video.getId());
                }
            }
            videoMapper.addRelation(memberVideoEntity);
        };
        if (faceSampleIds.isEmpty()) {
            // 没有人脸样本
            if (!sourceList.isEmpty()) {
                // 但是有原片
                task.callback.onInvoke();
            }
        } else {
            VideoPieceGetter.addTask(task);
        }
    }

    @Override
    public void autoCreateTaskByFaceId(Long faceId) {
        FaceRespVO faceRespVO = faceMapper.getById(faceId);
        if (faceRespVO == null) {
            log.info("faceId:{} is not exist", faceId);
            return;
        }
        if (!StringUtils.isNotBlank(faceRespVO.getMatchSampleIds())) {
            log.info("faceId:{} matchSampleIds is empty", faceId);
            return;
        }
        List<FaceSampleEntity> faceSampleList = faceSampleMapper.listByIds(Arrays.stream(faceRespVO.getMatchSampleIds().split(",")).filter(StringUtils::isNumeric).map(Long::valueOf).collect(Collectors.toList()));
        if (faceSampleList.isEmpty()) {
            log.info("faceId:{} faceSampleList is empty", faceId);
            return;
        }
        ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(faceRespVO.getScenicId());
        List<TemplateRespVO> templateList = templateRepository.getTemplateListByScenicId(faceRespVO.getScenicId());
        if (templateList == null || templateList.isEmpty()) {
            // 没有vlog视频的情况下
            VideoPieceGetter.Task task = new VideoPieceGetter.Task();
            task.faceId = faceId;
            task.faceSampleIds = faceSampleList.stream().map(FaceSampleEntity::getId).toList();
            task.templateId = null;
            task.memberId = faceRespVO.getMemberId();
            task.callback = () -> {
                log.info("task callback: {}", task);
            };
            VideoPieceGetter.addTask(task);
            return;
        }
        if (Integer.valueOf(3).equals(scenicConfig.getBookRoutine()) || Integer.valueOf(4).equals(scenicConfig.getBookRoutine())) {
            // 生成全部视频的逻辑
            templateList.forEach(template -> createTaskByFaceIdAndTempalteId(faceId, template.getId(), 1));
        } else {
            createTaskByFaceIdAndTempalteId(faceId, templateList.getFirst().getId(), 1);
        }
    }
    @Override
    public void createTaskByFaceIdAndTempalteId(Long faceId, Long templateId) {
        createTaskByFaceIdAndTempalteId(faceId, templateId, 0);
    }

    @Override
    public void createTaskByFaceIdAndTempalteId(Long faceId, Long templateId, int automatic) {
        FaceEntity face = faceRepository.getFace(faceId);
        if (face == null) {
            log.info("faceId:{} is not exist", faceId);
            return;
        }
        List<FaceSampleEntity> faceSampleList = faceRepository.getFaceSampleList(faceId);
        if (faceSampleList.isEmpty()) {
            log.info("faceId:{} sample list not exist", faceId);
        }
        if (templateBiz.determineTemplateCanGenerate(templateId, faceId, false)) {
            // 临时写死，当自动生成视频，切片也算合成中，并更新状态
            taskStatusBiz.setFaceCutStatus(face.getId(), 0);
        } else {
            taskStatusBiz.setFaceCutStatus(face.getId(), 2);
        }
        List<Long> faceSampleIds = faceSampleList.stream().map(FaceSampleEntity::getId).collect(Collectors.toList());
//        ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(face.getScenicId());
//        if (automatic > 0) {
//            TaskReqQuery taskReqQuery = new TaskReqQuery();
//            taskReqQuery.setFaceId(faceId);
//            taskReqQuery.setTemplateId(templateId);
//            List<TaskRespVO> list = taskMapper.list(taskReqQuery);
//            if (!list.isEmpty()) {
//                list.parallelStream().forEach(task -> {
//                    MemberVideoEntity memberVideo = videoMapper.queryRelationByMemberTask(faceRespVO.getMemberId(), task.getId());
//                    if (memberVideo == null) {
//                        memberVideo = new MemberVideoEntity();
//                        memberVideo.setMemberId(faceRespVO.getMemberId());
//                        memberVideo.setScenicId(task.getScenicId());
//                        memberVideo.setFaceId(faceId);
//                        memberVideo.setTemplateId(task.getTemplateId());
//                        if (Integer.valueOf(1).equals(scenicConfig.getAllFree())) {
//                            memberVideo.setIsBuy(1);
//                        } else {
//                            memberVideo.setIsBuy(0);
//                        }
//                        memberVideo.setTaskId(task.getId());
//                        VideoEntity video = videoMapper.findByTaskId(task.getId());
//                        if (video != null) {
//                            memberVideo.setVideoId(video.getId());
//                        }
//                        videoMapper.addRelation(memberVideo);
//                        new Thread(() -> {
//                            sendVideoGeneratedServiceNotification(list.getFirst().getId(), faceRespVO.getMemberId());
//                        }).start();
//                    }
//                });
//                return;
//            }
//        }
        VideoPieceGetter.Task task = new VideoPieceGetter.Task();
        task.faceId = faceId;
        task.faceSampleIds = faceSampleIds;
        task.templateId = templateId;
        task.memberId = face.getMemberId();
        task.callback = () -> {
            log.info("task callback: {}", task);
            boolean canGenerate = templateBiz.determineTemplateCanGenerate(templateId, faceId);
            if (!canGenerate) {
                log.info("task callback: 不能生成，templateId: {}", templateId);
                return;
            }
            List<SourceEntity> videoSourceList = sourceMapper.listVideoByScenicFaceRelation(face.getScenicId(), faceId);
            if (videoSourceList == null || videoSourceList.isEmpty()) {
                log.info("task callback: 没有视频源，templateId: {}", templateId);
                return;
            }
            Map<String, List<SourceEntity>> sourcesMap = videoSourceList.stream()
                    .peek(item -> item.setUrl(item.getVideoUrl()))
                    .filter(item -> {
                        DeviceEntity device = deviceRepository.getDevice(item.getDeviceId());
                        return Integer.valueOf(1).equals(device.getStatus());
                    })
                    .filter(item -> item.getDeviceId() != null) // 添加对 deviceId 为 null 的检查
                    .collect(Collectors.groupingBy(item -> item.getDeviceId().toString()));
            if (sourcesMap.isEmpty()) {
                // 主动禁止没有视频源视频生成
                log.info("task callback: 没有视频源，templateId: {}", templateId);
                return;
            }
            List<String> templatePlaceholder = templateRepository.getTemplatePlaceholder(templateId);
            if (templatePlaceholder.stream().distinct().count() == templatePlaceholder.size()) {
                sourcesMap.forEach((key, value) -> {
                    // 每个value只保留第一个
                    value.removeIf(item -> !value.getFirst().equals(item));
                });
            } else {
                log.info("task callback: 模板占位符有重复，templateId: {}", templateId);
            }
            TaskReqQuery taskReqQuery = new TaskReqQuery();
            taskReqQuery.setFaceId(faceId);
            taskReqQuery.setTemplateId(templateId);
            taskReqQuery.setTaskParams(JSON.toJSONString(sourcesMap));
            List<TaskRespVO> list = taskMapper.list(taskReqQuery);

            MemberVideoEntity memberVideoEntity = new MemberVideoEntity();
            memberVideoEntity.setMemberId(face.getMemberId());
            memberVideoEntity.setScenicId(face.getScenicId());
            memberVideoEntity.setFaceId(faceId);
            memberVideoEntity.setTemplateId(templateId);
            memberVideoEntity.setIsBuy(0);
            if (list.isEmpty()) {
                log.info("创建任务! faceId:{},templateId:{},taskParams:{}", faceId, templateId, sourcesMap);
                ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(face.getScenicId());
                TaskEntity taskEntity = null;
                if (Integer.valueOf(0).equals(scenicConfig.getTemplateNewVideoType())) {
                    log.info("景区{}启用：templateNewVideoType：全新视频原位替换", face.getScenicId());
                    taskReqQuery.setTemplateId(templateId);
                    List<TaskEntity> templateTaskList = taskMapper.listEntity(taskReqQuery);
                    if (!templateTaskList.isEmpty()) {
                        taskEntity = templateTaskList.getFirst();
                        log.info("已有旧生成的视频：{}", taskEntity);
                        MemberVideoEntity taskVideoRelation = videoMapper.queryRelationByMemberTask(face.getMemberId(), taskEntity.getId());
                        if (taskVideoRelation != null) {
                            log.info("已有旧关联记录的视频：{}", taskVideoRelation);
                            memberVideoEntity.setIsBuy(taskVideoRelation.getIsBuy());
                            memberVideoEntity.setOrderId(taskVideoRelation.getOrderId());
                        }
                        taskMapper.deleteById(taskEntity.getId());
                    }
                }
                if (taskEntity == null) {
                    taskEntity = new TaskEntity();
                    taskEntity.setId(SnowFlakeUtil.getLongId());
                    taskEntity.setScenicId(face.getScenicId());
                    taskEntity.setFaceId(faceId);
                    taskEntity.setTemplateId(templateId);
                    taskEntity.setAutomatic(automatic);
                }
                taskEntity.setWorkerId(null);
                taskEntity.setStatus(0);
                taskEntity.setTaskParams(JSON.toJSONString(sourcesMap));
                taskMapper.add(taskEntity);
                memberVideoEntity.setTaskId(taskEntity.getId());
            } else {
                log.info("重复task! faceId:{},templateId:{},taskParams:{}", faceId, templateId, sourcesMap);
                memberVideoEntity.setTaskId(list.getFirst().getId());
                VideoEntity video = videoMapper.findByTaskId(list.getFirst().getId());
                if (video != null) {
                    IsBuyRespVO isBuy = orderBiz.isBuy(face.getMemberId(), list.getFirst().getScenicId(), 0, video.getId());
                    if (isBuy.isBuy()) {
                        memberVideoEntity.setIsBuy(1);
                        memberVideoEntity.setOrderId(isBuy.getOrderId());
                    }
                    if (isBuy.isFree()) {
                        memberVideoEntity.setIsBuy(1);
                    }
                    memberVideoEntity.setVideoId(video.getId());
                }
            }
            videoMapper.addRelation(memberVideoEntity);
            // 任务生成了，需要更新切割任务状态
            taskStatusBiz.setFaceCutStatus(faceId, 2);
        };
        if (faceSampleIds.isEmpty()) {
            // 没有人脸样本
            task.callback.onInvoke();
        } else {
            VideoPieceGetter.addTask(task);
        }
    }

    @Override
    public void taskSuccess(@NonNull Long taskId, @NonNull TaskSuccessReqVo req) {
        TaskRespVO task = taskMapper.getById(taskId);
        if (task == null) {
            return;
        }
        RenderWorkerEntity worker = getWorker(req);
        if (worker == null) {
            return;
        }
        TaskEntity taskUpdate = new TaskEntity();
        taskUpdate.setId(taskId);
        taskUpdate.setStatus(1);
        taskUpdate.setWorkerId(worker.getId());
        taskMapper.setSuccess(taskUpdate);
        videoTaskRepository.clearTaskCache(taskUpdate.getId());

        VideoEntity video = videoMapper.findByTaskId(taskId);
        if (video != null) {
            video.setVideoUrl(task.getVideoUrl());
            if (req.getVideoInfo() != null) {
                video.setHeight(req.getVideoInfo().getHeight());
                video.setWidth(req.getVideoInfo().getWidth());
                video.setDuration(req.getVideoInfo().getDuration());
            }
            videoMapper.update(video);
            videoRepository.clearVideoCache(video.getId());
        } else {
            video = new VideoEntity();
            video.setId(SnowFlakeUtil.getLongId());
            video.setScenicId(task.getScenicId());
            video.setTemplateId(task.getTemplateId());
            video.setTaskId(taskId);
            video.setWorkerId(worker.getId());
            video.setVideoUrl(task.getVideoUrl());
            video.setCreateTime(new Date());
            if (req.getVideoInfo() != null) {
                video.setHeight(req.getVideoInfo().getHeight());
                video.setWidth(req.getVideoInfo().getWidth());
                video.setDuration(req.getVideoInfo().getDuration());
            }
            videoMapper.add(video);
        }
        ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(task.getScenicId());
        IStorageAdapter adapter = scenicService.getScenicTmpStorageAdapter(task.getScenicId());
        String filename = StorageUtil.joinPath(StorageConstant.VLOG_PATH, task.getId() + "_" + task.getScenicId() + ".mp4");
        adapter.setAcl(StorageAcl.PUBLIC_READ, filename);
        videoReUploader.addVideoTask(video.getId());
        int isBuy = 0;
        FaceEntity face = faceRepository.getFace(task.getFaceId());
        if (face != null) {
            IsBuyRespVO priceObj = orderBiz.isBuy(face.getMemberId(), task.getScenicId(), 0, video.getId());
            if (priceObj.isBuy()) {
                isBuy = 1;
            }
            if (priceObj.isFree()) {
                isBuy = 1;
            }
            if (isBuy != 1) {
                // 判断景区新生成免费送逻辑
                if (scenicConfig != null && Integer.valueOf(2).equals(scenicConfig.getTemplateNewVideoType())) {
                    log.info("景区{}启用：templateNewVideoType：全新视频不需要重新购买", task.getScenicId());
                    // 全新视频，不需要重新购买，旧视频在我的里面查看
                    List<MemberVideoEntity> entityList = videoMapper.listRelationByFaceAndTemplate(face.getId(), task.getTemplateId());
                    Optional<MemberVideoEntity> buy = entityList.stream().filter(item -> Integer.valueOf(1).equals(item.getIsBuy())).findAny();
                    if (buy.isPresent()) {
                        log.info("人脸{}，模板{}，已经被购买过，{}", face.getId(), task.getTemplateId(), buy.get());
                        // 买过
                        isBuy = 1;
                    }
                }
            }
        }
        videoMapper.updateRelationWhenTaskSuccess(taskId, video.getId(), isBuy);
        new Thread(() -> sendVideoGeneratedServiceNotification(taskId)).start();
    }

    @Override
    public void taskFail(Long taskId, WorkerAuthReqVo req) {
        TaskRespVO task = taskMapper.getById(taskId);
        if (task == null) {
            return;
        }
        RenderWorkerEntity worker = getWorker(req);
        if (worker == null) {
            return;
        }
        TaskEntity taskUpdate = new TaskEntity();
        taskUpdate.setId(taskId);
        taskUpdate.setStatus(2);
        taskUpdate.setWorkerId(worker.getId());
        taskMapper.setFail(taskUpdate);
        taskMapper.deassign(taskId);
        videoTaskRepository.clearTaskCache(taskUpdate.getId());
    }

    @Override
    public String getUploadUrl(Long taskId, WorkerAuthReqVo req) {
        TaskRespVO task = taskMapper.getById(taskId);
        if (task == null) {
            return null;
        }
        RenderWorkerEntity worker = getWorker(req);
        if (worker == null) {
            return null;
        }
        IStorageAdapter adapter;
        try {
            adapter = StorageFactory.get(worker.getStoreType());
            adapter.loadConfig(JSONObject.parseObject(worker.getStoreConfigJson(), Map.class));
        } catch (Exception e) {
            adapter = scenicService.getScenicStorageAdapter(task.getScenicId());
        }
        String filename = StorageUtil.joinPath(StorageConstant.VLOG_PATH, task.getId() + "_" + task.getScenicId() + ".mp4");
        // 生成
        String url = adapter.getUrl(filename);
        TaskEntity updateTask = new TaskEntity();
        updateTask.setId(taskId);
        updateTask.setVideoUrl(url);
        taskMapper.update(updateTask);
        videoTaskRepository.clearTaskCache(updateTask.getId());
        return adapter.getUrlForUpload(new Date(System.currentTimeMillis() + 1000 * 3600), "video/mp4", filename);
    }

    public void sendVideoGeneratedServiceNotification(Long taskId) {
        List<MemberVideoEntity> memberVideo = videoMapper.listRelationByTask(taskId);
        memberVideo.forEach(item -> sendVideoGeneratedServiceNotification(taskId, item.getMemberId()));
    }

    @Override
    public Date getTaskShotDate(Long taskId) {
        TaskRespVO taskRespVO = taskMapper.getById(taskId);
        if (taskRespVO == null) {
            return null;
        }
        Date shotTime = taskRespVO.getCreateTime();
        JSONObject paramJson = JSON.parseObject(taskRespVO.getTaskParams());
        if (paramJson != null) {
            Optional<String> any = paramJson.keySet().stream().filter(StringUtils::isNumeric).findAny();
            if (any.isPresent()) {
                JSONArray jsonArray = paramJson.getJSONArray(any.get());
                if (!jsonArray.isEmpty()) {
                    JSONObject jsonObject = jsonArray.getJSONObject(0);
                    if (jsonObject.containsKey("createTime")) {
                        shotTime = new Date(jsonObject.getLong("createTime"));
                    }
                }
            }
        }
        return shotTime;
    }

    @Override
    public void sendVideoGeneratedServiceNotification(Long taskId, Long memberId) {
        MemberVideoEntity item = videoMapper.queryRelationByMemberTask(memberId, taskId);
        MemberRespVO member = memberMapper.getById(memberId);
        String openId = member.getOpenId();
        MpConfigEntity scenicMp = scenicRepository.getScenicMpConfig(member.getScenicId());
        if (StringUtils.isNotBlank(openId) && scenicMp != null) {
            String templateId = scenicRepository.getVideoGeneratedTemplateId(item.getScenicId());
            if (StringUtils.isBlank(templateId)) {
                log.warn("未配置视频生成通知模板");
                return;
            }
            ScenicEntity scenic = scenicRepository.getScenic(item.getScenicId());
            String title = "您在【" + scenic.getName() + "】的专属影像";
            String page = "pages/videoSynthesis/index?type=1&scenicId=" + item.getScenicId() + "&faceId=" + item.getFaceId();
            /**
             * 视频名称 {{thing1.DATA}}
             * 生成时间 {{time4.DATA}}
             * 备注 {{thing3.DATA}}
             */
            Map<String, Object> params = new HashMap<>();
            Map<String, Object> dataParam = new HashMap<>();
            Map<String, String> videoMap = new HashMap<>();
            videoMap.put("value", title);
            dataParam.put("thing1", videoMap);
            Map<String, String> timeMap2 = new HashMap<>();
            timeMap2.put("value", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm"));
            dataParam.put("time4", timeMap2);
            Map<String, String> remarkMap = new HashMap<>();
            remarkMap.put("value", "请及时查看视频，48小时后系统删除");
            dataParam.put("thing3", remarkMap);
            params.put("data", dataParam);
            params.put("page", page);
            params.put("template_id", templateId);
            log.info("视频生成通知模板参数：{}，用户ID：{}", params, openId);
            INotifyAdapter adapter = NotifyFactory.get(NotifyType.WX_MP_SRV, scenicMp.toMap());
            adapter.sendTo(new NotifyContent(title, page, params), openId);
        }
    }

    @Override
    public TaskRespVO taskInfo(Long taskId) {
        return taskMapper.getById(taskId);
    }
}
