package cn.iocoder.byzs.module.blockly.service.blockly;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.byzs.framework.common.pojo.PageResult;
import cn.iocoder.byzs.framework.common.util.object.BeanUtils;
import cn.iocoder.byzs.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.byzs.module.blockly.controller.admin.blockly.vo.BlocklyPageReqVO;
import cn.iocoder.byzs.module.blockly.controller.admin.blockly.vo.BlocklyRespVO;
import cn.iocoder.byzs.module.blockly.controller.admin.blockly.vo.BlocklySaveReqVO;
import cn.iocoder.byzs.module.blockly.dal.dataobject.blockly.BlocklyDO;
import cn.iocoder.byzs.module.blockly.dal.dataobject.blocklyProgress.BlocklyProgressDO;
import cn.iocoder.byzs.module.blockly.dal.dataobject.blocklyType.BlocklyTypeDO;
import cn.iocoder.byzs.module.blockly.dal.mysql.blockly.BlocklyMapper;
import cn.iocoder.byzs.module.blockly.dal.mysql.blocklyProgress.BlocklyProgressMapper;
import cn.iocoder.byzs.module.blockly.dal.mysql.blocklyType.BlocklyTypeMapper;
import cn.iocoder.byzs.module.infra.dal.dataobject.file.FileDO;
import cn.iocoder.byzs.module.infra.framework.file.core.client.FileClient;
import cn.iocoder.byzs.module.infra.service.file.FileConfigService;
import cn.iocoder.byzs.module.infra.service.file.FileServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.util.List;
import java.util.stream.Collectors;

import static cn.iocoder.byzs.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.byzs.module.blockly.enums.ErrorCodeConstants.*;

/**
 * 课程 Service 实现类
 *
 * @author lyb
 */
@Service
@Validated
public class BlocklyServiceImpl implements BlocklyService {

    @Resource
    private BlocklyMapper blocklyMapper;
    @Resource
    private BlocklyTypeMapper blocklyTypeMapper;
    @Resource
    private FileServiceImpl fileService;
    @Resource
    private FileConfigService fileConfigService;
    @Resource
    private BlocklyProgressMapper blocklyProgressMapper;

    @Override
    public Long createBlockly(BlocklySaveReqVO createReqVO) {
        // 插入
        BlocklyDO blockly = BeanUtils.toBean(createReqVO, BlocklyDO.class);
        blocklyMapper.insert(blockly);

        if (blockly.getBcContentType().equals("video")) {
            getSelf().asymcVideoFfmpeg(blockly);
        }
        // 返回
        return blockly.getId();
    }

    @Override
    public void updateBlockly(BlocklySaveReqVO updateReqVO) {
        // 校验存在
        BlocklyDO blocklyDO = validateBlocklyExists(updateReqVO.getId());
        // 更新
        BlocklyDO updateObj = BeanUtils.toBean(updateReqVO, BlocklyDO.class);
        blocklyMapper.updateById(updateObj);

        //同步进度表中的课程类型
        if (!blocklyDO.getBcType().equals(updateObj.getBcType())) {
            BlocklyTypeDO blocklyTypeDO = blocklyTypeMapper.selectById(updateObj.getBcType());
            // 使用条件更新，将brpCtId等于旧课程类型ID的记录更新为新课程类型ID
            blocklyProgressMapper.update(new BlocklyProgressDO().setBrpCtId(updateObj.getBcType()).setBrpZtId(blocklyTypeDO.getCtParentId()),
                                         new LambdaQueryWrapperX<BlocklyProgressDO>().eq(BlocklyProgressDO::getBrpCtId, blocklyDO.getBcType()));
        }

        if (updateObj.getBcContentType().equals("video")) {
            getSelf().asymcVideoFfmpeg(updateObj);
        }
    }

    @Async
    public void asymcVideoFfmpeg(BlocklyDO blockly) {
        //只对mp4文件进行处理
        String blocklyVideoPath = blockly.getBcContent();
        String ext = blocklyVideoPath.substring(blocklyVideoPath.lastIndexOf("."));
        if (StrUtil.isBlank(ext) || ext.equals(".m3u8")) {
            return;
        }

        //获取相对文件路径
        FileDO fileDO= fileService.getFilePathByUrl(blockly.getBcContent());
        if (fileDO == null || fileDO.getPath() == null) {
            return;
        }

        //切片
        FileClient client = fileConfigService.getMasterFileClient();
        String m3u8Path = client.ffmpegHts(fileDO.getPath());
        if(StrUtil.isNotEmpty(m3u8Path)){
            blocklyMapper.updateById(new BlocklyDO().setId(blockly.getId()).setBcContent(m3u8Path));
            fileDO.setUrl(m3u8Path);
            fileService.updateFileById(fileDO);

            // 从文件存储器中删除【暂时不删除mp4文件，删除时需要同步更改fileDo中path的相对路径更改成m3u8文件】
//            try {
//                client.delete(blocklyVideoPath);
//            } catch (Exception e) {
//                throw new RuntimeException(e);
//            }
        }
    }

    @Override
    public void deleteBlockly(Long id) {
        // 校验存在
        validateBlocklyExists(id);
        // 删除
        blocklyMapper.deleteById(id);
    }

    @Override
        public void deleteBlocklyListByIds(List<Long> ids) {
        // 校验存在
        validateBlocklyExists(ids);
        // 删除
        blocklyMapper.deleteByIds(ids);
        }

    private void validateBlocklyExists(List<Long> ids) {
        List<BlocklyDO> list = blocklyMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(BLOCKLY_NOT_EXISTS);
        }
    }

    private BlocklyDO validateBlocklyExists(Long id) {
        BlocklyDO blocklyDO = blocklyMapper.selectById(id);
        if (blocklyDO == null) {
            throw exception(BLOCKLY_NOT_EXISTS);
        }
        return blocklyDO;
    }

    @Override
    public BlocklyDO getBlockly(Long id) {
        return blocklyMapper.selectById(id);
    }

    @Override
    public PageResult<BlocklyRespVO> getBlocklyPage(BlocklyPageReqVO pageReqVO) {
        pageReqVO.setPageNo((pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize());
        List<BlocklyPageReqVO> blocklyPageReqVOS = blocklyMapper.selectBlocklyPage(pageReqVO);

        // 获取总记录数
        int total = blocklyMapper.selectBlocklyPageCount(pageReqVO);
        // 调用服务层方法获取分页结果
        return new PageResult<>(
                blocklyPageReqVOS.stream()
                        .map(doItem -> BeanUtils.toBean(doItem, BlocklyRespVO.class))
                        .collect(Collectors.toList()),
                (long) total
        );
    }

    @Override
    public List<BlocklyPageReqVO> getBlocklyList(BlocklyPageReqVO pageReqVO) {
        return blocklyMapper.selectBlocklyList(pageReqVO);
    }

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

}