/**
 * 20241029 ©WANGKANG 1686617586@qq.com
 */

package com.taais.biz.service.impl;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

import cn.hutool.core.util.ObjectUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.taais.biz.domain.Video2image;
import com.taais.biz.domain.bo.Video2imageBo;
import com.taais.biz.domain.vo.Video2imageVo;
import com.taais.biz.mapper.Video2imageMapper;
import com.taais.biz.service.IVideo2imageService;
import com.taais.common.core.config.TaaisConfig;
import com.taais.common.core.constant.Constants;
import com.taais.common.core.utils.MapstructUtils;
import com.taais.common.core.utils.StringUtils;
import com.taais.common.orm.core.page.PageQuery;
import com.taais.common.core.core.page.PageResult;
import com.taais.common.orm.core.service.impl.BaseServiceImpl;
import com.taais.system.domain.vo.SysOssVo;
import com.taais.system.service.ISysOssService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import static com.taais.biz.constant.BizConstant.UPLOAD_DIR;
import static com.taais.biz.constant.BizConstant.VideoStatus.*;
import static com.taais.biz.domain.table.Video2imageTableDef.VIDEO2IMAGE;
import static com.taais.biz.service.impl.VideoStableServiceImpl.removeFileExtension;

import com.taais.biz.utils.VideoCapture;
import com.taais.biz.utils.ZipUtils;

/**
 * 视频转图片 Service业务层处理
 *
 * @author km
 * 2024-08-16
 */
@Service
@Slf4j
public class Video2imageServiceImpl extends BaseServiceImpl<Video2imageMapper, Video2image> implements IVideo2imageService {
    @Autowired
    private ISysOssService ossService;

    @Override
    public QueryWrapper query() {
        return super.query().from(VIDEO2IMAGE);
    }

    public Map<Long, Thread> threads = new java.util.concurrent.ConcurrentHashMap();

    private QueryWrapper buildQueryWrapper(Video2imageBo video2imageBo) {
        QueryWrapper queryWrapper = super.buildBaseQueryWrapper();
        queryWrapper.and(VIDEO2IMAGE.NAME.like
            (video2imageBo.getName()));
        queryWrapper.and(VIDEO2IMAGE.STATUS.eq
            (video2imageBo.getStatus()));
        queryWrapper.and(VIDEO2IMAGE.OUT_PATH.eq
            (video2imageBo.getOutPath()));
        queryWrapper.and(VIDEO2IMAGE.START_TIME.eq
            (video2imageBo.getStartTime()));
        queryWrapper.and(VIDEO2IMAGE.END_TIME.eq
            (video2imageBo.getEndTime()));
        queryWrapper.and(VIDEO2IMAGE.COST_SECOND.eq
            (video2imageBo.getCostSecond()));
        queryWrapper.and(VIDEO2IMAGE.LOG.like
            (video2imageBo.getLog()));
        queryWrapper.and(VIDEO2IMAGE.REMARKS.like
            (video2imageBo.getRemarks()));
        queryWrapper.and(VIDEO2IMAGE.PATH.eq
            (video2imageBo.getPath()));
        queryWrapper.and(VIDEO2IMAGE.FPS.eq
            (video2imageBo.getFps()));

        return queryWrapper;
    }

    /**
     * 查询视频转图片
     *
     * @param id 视频转图片主键
     * @return 视频转图片
     */
    @Override
    public Video2imageVo selectById(Long id) {
        return this.getOneAs(query().where(VIDEO2IMAGE.ID.eq(id)), Video2imageVo.class);

    }

    /**
     * 查询视频转图片列表
     *
     * @param video2imageBo 视频转图片Bo
     * @return 视频转图片集合
     */
    @Override
    public List<Video2imageVo> selectList(Video2imageBo video2imageBo) {
        QueryWrapper queryWrapper = buildQueryWrapper(video2imageBo);
        return this.listAs(queryWrapper, Video2imageVo.class);
    }

    /**
     * 分页查询视频转图片列表
     *
     * @param video2imageBo 视频转图片Bo
     * @return 分页视频转图片集合
     */
    @Override
    public PageResult<Video2imageVo> selectPage(Video2imageBo video2imageBo) {
        QueryWrapper queryWrapper = buildQueryWrapper(video2imageBo);
        Page<Video2imageVo> page = this.pageAs(PageQuery.build(), queryWrapper, Video2imageVo.class);
        return PageResult.build(page);
    }

    /**
     * 新增视频转图片
     *
     * @param video2imageBo 视频转图片Bo
     * @return 结果:true 操作成功，false 操作失败
     */
    @Override
    public boolean insert(Video2imageBo video2imageBo) {
        // 检查input_oss_id是否存在
        if (ObjectUtil.isNull(video2imageBo.getInputOssId())) {
            return false;
        }

        SysOssVo ossEntity = ossService.getById(video2imageBo.getInputOssId());
        if (ObjectUtil.isNull(ossEntity)) {
            return false;
        }

        Video2image newVideo2image = new Video2image();

        newVideo2image.setInputOssId(video2imageBo.getInputOssId());
        newVideo2image.setUrl(ossEntity.getUrl());

        String filePath = ossEntity.getFileName();
        String localPath = TaaisConfig.getProfile();
        String resourcePath = localPath + StringUtils.substringAfter(filePath, Constants.RESOURCE_PREFIX);
        newVideo2image.setPath(resourcePath);

        String fileName = StringUtils.substringAfterLast(filePath, "/");
        String fileName_without_suffix = removeFileExtension(fileName);

        Path path = Paths.get(resourcePath);
        Path outPath = path.resolveSibling(fileName_without_suffix + "_images" + System.currentTimeMillis());
        newVideo2image.setOutPath(outPath.toString());

        newVideo2image.setZipFilePath(path.resolveSibling(fileName_without_suffix + ".zip").toString());

        newVideo2image.setName(video2imageBo.getName());
        newVideo2image.setFps(video2imageBo.getFps());
        newVideo2image.setStatus(NOT_START);
        newVideo2image.setRemarks(video2imageBo.getRemarks());

        return this.save(newVideo2image);// 使用全局配置的雪花算法主键生成器生成ID值
    }

    /**
     * 修改视频转图片
     *
     * @param video2imageBo 视频转图片Bo
     * @return 结果:true 更新成功，false 更新失败
     */
    @Override
    public boolean update(Video2imageBo video2imageBo) {
        Video2image video2image = MapstructUtils.convert(video2imageBo, Video2image.class);
        if (ObjectUtil.isNotNull(video2image) && ObjectUtil.isNotNull(video2image.getId())) {
            boolean updated = this.updateById(video2image);
            return updated;
        }
        return false;
    }

    /**
     * 批量删除视频转图片
     *
     * @param ids 需要删除的视频转图片主键集合
     * @return 结果:true 删除成功，false 删除失败
     */
    @Transactional
    @Override
    public boolean deleteByIds(Long[] ids) {
        return this.removeByIds(Arrays.asList(ids));
    }


    public void updateStatus(Long id, String log, String status) {
        Video2image video2image = this.getById(id);
        video2image.setStatus(status);
        video2image.setLog(log);
        video2image.setEndTime(new Date());
        video2image.setCostSecond((video2image.getEndTime().getTime() - video2image.getStartTime().getTime()) / 1000);
        this.updateById(video2image);
    }

    @Override
    public boolean startToImage(Long id) {
        Video2image video2image = this.getById(id);
        if (ObjectUtil.isNull(video2image)) {
            log.info("ObjectUtil.isNotNull(video2image)...");
            return false;
        }
        log.info("开始截取图片...");

        String videoPath = video2image.getPath();
        String outPath = video2image.getOutPath();
        Long fps = video2image.getFps();

        log.info("videoPath: " + videoPath);
        log.info("outPath: " + outPath);
        log.info("fps: " + fps);

        // File file = new File(videoPath);
        // if (!file.exists() || !file.isFile()) {
        //     log.error("文件不存在...");
        //     return false;
        // }

        video2image.setStatus(RUNNING);
        video2image.setStartTime(new Date());
        video2image.setEndTime(null);
        video2image.setCostSecond(null);
        video2image.setLog("");
        this.updateById(video2image);


        Thread thread__ = new Thread(() -> {
            String log_str = "";
            log.info("开始截取图片子线程...");
            log.info("开始截取图片...");

            log_str += "开始截取图片子线程...\n";
            log_str += "开始截取图片...\n";
            boolean success = false;
            boolean interrupted = false;
            try {
                VideoCapture.startCaputreFromUrl(videoPath, outPath, fps);
                log.info("视频转图片结束...");
                log_str += "视频转图片结束...\n";

                log.info("开始压缩图片...");
                log_str += "开始压缩图片...\n";
                String zipFilePath = Paths.get(outPath).resolveSibling(video2image.getName() + ".zip").toString();
                ZipUtils.zipFolderFiles(outPath, zipFilePath);

                log_str += "压缩图片成功...\n";
                log.info("压缩图片成功...");
                success = true;
            } catch (InterruptedException e) {
                e.printStackTrace();
                log_str += "视频转图片子线程中断...\n" + e.getMessage() + "\n";
                log.error("视频转图片子线程中断...", e);
                interrupted = true;
            } catch (Exception e) {
                e.printStackTrace();
                log_str += "视频转图片出现未知错误...\n" + e.getMessage() + "\n";
                log.error("视频转图片出现未知错误...", e);
            } finally {
                if (success) {
                    System.out.println("更新状态为结束");
                    updateStatus(id, log_str, END);
                } else if (interrupted) {
                    System.out.println("更新状态为中断");
                    updateStatus(id, log_str, INTERRUPTED); // 子线程中断，更新状态为结束
                } else {
                    System.out.println("更新状态为失败");
                    updateStatus(id, log_str, FAILED); // 子线程中断，更新状态为结束
                }
                log.info("视频转图片子线程结束...");

                threads.remove(id);
            }
        });

        threads.put(id, thread__);

        thread__.start();

        return true;
    }

    @Override
    public ResponseEntity<Resource> zipImages(Long id) {
        Video2image video2image = this.getById(id);
        if (ObjectUtil.isNull(video2image)) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
        }

        String sourceFolderPath = video2image.getOutPath();
        String zipFilePath = Paths.get(sourceFolderPath).resolveSibling(video2image.getName() + ".zip").toString();

        File file = new File(zipFilePath);

        if (!file.exists() || !file.isFile()) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
        }

        org.springframework.core.io.Resource resource = new FileSystemResource(file);
        return ResponseEntity.ok()
            .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getName() + "\"")
            .header(HttpHeaders.CONTENT_TYPE, "application/octet-stream")
            .body(resource);
    }

    @Override
    public boolean stopToImage(Long id) {
        if (threads.containsKey(id)) {
            Thread thread = threads.get(id);
            System.out.println("--------------------1");

            System.out.println("stopToImage..." + thread.toString() + "   " + thread.isAlive());
            if (ObjectUtil.isNotNull(thread)) {
                System.out.println("--------------------2");

                thread.interrupt();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("stopToImage..." + thread.toString() + "   " + thread.isAlive());
                threads.remove(id);

                return true;
            }
        }
        return false;
    }
}
