package com.backendsys.modules.crt.service.impl;

import com.backendsys.exception.CustException;
import com.backendsys.modules.common.config.security.enums.SecurityEnum;
import com.backendsys.modules.common.config.security.utils.SecurityUtil;
import com.backendsys.modules.common.enums.MatchType;
import com.backendsys.modules.crt.dao.CrtDramaProjectDao;
import com.backendsys.modules.crt.dao.CrtDramaProjectSettingsDao;
import com.backendsys.modules.crt.dao.CrtDramaProjectStoryboardDao;
import com.backendsys.modules.crt.dao.CrtGenerateImageDao;
import com.backendsys.modules.crt.entity.*;
import com.backendsys.modules.crt.service.CrtDramaProjectStoryboardService;
import com.backendsys.modules.upload.entity.ObjectKey;
import com.backendsys.modules.upload.enums.StyleEnums;
import com.backendsys.modules.upload.utils.ObjectKey.ObjectKeyUtil;
import com.backendsys.modules.upload.utils.UploadUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Service
public class CrtDramaProjectStoryboardServiceImpl implements CrtDramaProjectStoryboardService {

    @Autowired
    private ObjectKeyUtil objectKeyUtil;
    @Autowired
    private SecurityUtil securityUtil;
    @Autowired
    private CrtDramaProjectDao crtDramaProjectDao;
    @Autowired
    private CrtGenerateImageDao crtGenerateImageDao;
    @Autowired
    private CrtDramaProjectSettingsDao crtDramaProjectSettingsDao;
    @Autowired
    private CrtDramaProjectStoryboardDao crtDramaProjectStoryboardDao;

    /**
     * 获取分集信息/分镜列表
     */
    @Override
    public StoryboardResponse selectCrtDramaProjectStoryboardDetail(CrtDramaProjectStoryboard crtDramaProjectStoryboard) {

        Long project_id = crtDramaProjectStoryboard.getDrama_project_id();

        CrtDramaProject crtDramaProject = crtDramaProjectDao.selectById(project_id);
        if (crtDramaProject == null) throw new CustException("项目不存在");

        List<CrtDramaProjectStoryboard> storyboardList = crtDramaProjectStoryboardDao.selectStoryboardList(crtDramaProjectStoryboard);
        if (storyboardList != null && storyboardList.isEmpty()) throw new CustException("分镜不存在");

        // 获取分镜列表
        storyboardList.stream().forEach(storyboard -> {
            // 获取分镜生图结果
            if (storyboard.getGenerate_images() != null && !storyboard.getGenerate_images().isEmpty()) {
                // 设置生图结果缩略略
                List<CrtGenerateImage> generate_image_list = storyboard.getGenerate_images().stream().map(item -> {
                    String url = item.getUrl();
                    Integer target = item.getTarget();
                    String url_thumb = UploadUtil.getImageThumbUrl(url, target, 100, null, StyleEnums.THUMB_BACKGROUND.getValue());
                    item.setUrl_thumb(url_thumb);
                    return item;
                }).collect(Collectors.toList());
                storyboard.setGenerate_images(generate_image_list);
            }
        });

        // 查询项目设置
        LambdaQueryWrapper<CrtDramaProjectSettings> wrapperSettings = new LambdaQueryWrapper<>();
        wrapperSettings.eq(CrtDramaProjectSettings::getDrama_project_id, project_id);
        List<CrtDramaProjectSettings> settingsList = crtDramaProjectSettingsDao.selectList(wrapperSettings);

        // 获取项目详情与分镜列表
        StoryboardResponse storyboardResponse = new StoryboardResponse();
        storyboardResponse.setDrama_project_id(project_id);
        storyboardResponse.setProject_name(crtDramaProject.getProject_name());
        storyboardResponse.setStoryboard_list(storyboardList);

        if (settingsList.size() > 0) {
            settingsList.stream().forEach(settings -> {
                // 项目配置类型 (1: 生图配置, 2: 生视频配置)
                if (settings.getDrama_project_setting_type() == 1) storyboardResponse.setSettings_image(settings);
                if (settings.getDrama_project_setting_type() == 2) storyboardResponse.setSettings_video(settings);
            });
        }

        return storyboardResponse;
    }

    /**
     * 创建分集
     */
    @Override
    public Map<String, Object> createStoryboard(CrtDramaProjectStoryboard crtDramaProjectStoryboard) {

        Long user_id = crtDramaProjectStoryboard.getUser_id();
        Long drama_project_id = crtDramaProjectStoryboard.getDrama_project_id();
        Integer episode_num = crtDramaProjectStoryboard.getEpisode_num();
        Integer sort = crtDramaProjectStoryboard.getSort() == null ? 1 : crtDramaProjectStoryboard.getSort();

        // 判断 项目 是否存在
        LambdaQueryWrapper<CrtDramaProject> wrapperDramaProject = new LambdaQueryWrapper<>();
        wrapperDramaProject.eq(CrtDramaProject::getId, drama_project_id);
        Boolean is_exist_project = crtDramaProjectDao.exists(wrapperDramaProject);
        if (!is_exist_project) throw new CustException("项目不存在");

        // 不传 { sort } 即是初始化，初始化需要判断分镜是否存在
        LambdaQueryWrapper<CrtDramaProjectStoryboard> wrapperStoryboard = new LambdaQueryWrapper<>();
        wrapperStoryboard.eq(CrtDramaProjectStoryboard::getDrama_project_id, drama_project_id);
        wrapperStoryboard.eq(CrtDramaProjectStoryboard::getEpisode_num, episode_num);
        if (sort == null) {
            Boolean is_exist_storyboard = crtDramaProjectStoryboardDao.exists(wrapperStoryboard);
            if (is_exist_storyboard) throw new CustException("集数或分镜已存在，请勿重复创建");
        } else {
            wrapperStoryboard.eq(CrtDramaProjectStoryboard::getSort, sort);
            Boolean is_exist_storyboard = crtDramaProjectStoryboardDao.exists(wrapperStoryboard);
            if (is_exist_storyboard) throw new CustException("集数或分镜已存在，请勿重复创建");
        }

        // [DB] 创建分镜
        CrtDramaProjectStoryboard entity = new CrtDramaProjectStoryboard();
        entity.setUser_id(user_id);
        entity.setDrama_project_id(drama_project_id);
        entity.setEpisode_num(episode_num);
        entity.setSort(sort);
        crtDramaProjectStoryboardDao.insert(entity);

        return Map.of("id", entity.getId());
    }


    /**
     * 编辑分镜
     */
    @Override
    public Map<String, Object> updateStoryboard(CrtDramaProjectStoryboard crtDramaProjectStoryboard) {

        Long storyboard_id = crtDramaProjectStoryboard.getDrama_project_storyboard_id();
        CrtDramaProjectStoryboard storyboardDetail = crtDramaProjectStoryboardDao.selectById(storyboard_id);
        if (storyboardDetail == null) throw new CustException("分镜不存在");

        // 是否 [分镜] 拥有者，权限：
        // - 编辑自己的 (需 36.2.4.1 权限)
        // - 编辑自己及他人的 (需要 36.2.4 权限或超级管理员)
        Boolean isOwner = storyboardDetail.getUser_id() == SecurityUtil.getUserId();
        if (isOwner && !securityUtil.hasPermissions(Arrays.asList("36.2.4", "36.2.4.1"), MatchType.OR)) {
            throw new CustException(SecurityEnum.NOAUTH);
        }
        if (!isOwner && !securityUtil.hasPermission("36.2.4")) {
            throw new CustException(SecurityEnum.NOAUTH);
        }
        // ---------------------------------------------------------------------------

        // [DB] 更新分镜
        crtDramaProjectStoryboardDao.updateStoryboard(crtDramaProjectStoryboard);

        return Map.of("drama_project_storyboard_id", crtDramaProjectStoryboard.getDrama_project_storyboard_id());
    }

    /**
     * [Event] 删除全部分镜
     */
    private void eventDeleteStoryboard(Long drama_project_id, Integer episode_num) {
        LambdaQueryWrapper<CrtDramaProjectStoryboard> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CrtDramaProjectStoryboard::getDrama_project_id, drama_project_id);
        wrapper.eq(CrtDramaProjectStoryboard::getEpisode_num, episode_num);

        // [DB] 查询分镜
        List<CrtDramaProjectStoryboard> storyboardList = crtDramaProjectStoryboardDao.selectList(wrapper);
        if (storyboardList == null || storyboardList.isEmpty()) throw new CustException("分镜不存在");

        // 删除或清空全部，需要有项目的所有者权限
        CrtDramaProject dramaProjectDetail = crtDramaProjectDao.selectById(drama_project_id);
        if (dramaProjectDetail == null) throw new CustException("项目不存在");

        // 是否 [分镜] 拥有者，权限：
        // - 编辑自己的 (需 36.2.6.1 权限)
        // - 编辑自己及他人的 (需要 36.2.6 权限或超级管理员)
        Boolean isOwner = dramaProjectDetail.getUser_id() == SecurityUtil.getUserId();
        if (isOwner && !securityUtil.hasPermissions(Arrays.asList("36.2.6", "36.2.6.1"), MatchType.OR)) {
            throw new CustException(SecurityEnum.NOAUTH);
        }
        if (!isOwner && !securityUtil.hasPermission("36.2.6")) {
            throw new CustException(SecurityEnum.NOAUTH);
        }
        // ---------------------------------------------------------------------------

        // [DB] 清空当前分集的所有分镜
        crtDramaProjectStoryboardDao.delete(wrapper);

        // [DB/OBJ] 删除分镜下的生图内容 (批量删除 cos/tos)
        storyboardList.forEach(storyboard -> {
            deleteStoryboardImage(storyboard.getDrama_project_storyboard_id());
        });

    }

    /**
     * 清空全部分镜 (仅保留一个空分镜)
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> clearStoryboard(CrtDramaProjectStoryboard crtDramaProjectStoryboard) {

        Long drama_project_id = crtDramaProjectStoryboard.getDrama_project_id();
        Integer episode_num = crtDramaProjectStoryboard.getEpisode_num();

        // [Event] 删除全部分镜
        eventDeleteStoryboard(drama_project_id, episode_num);

        // [DB] 初始化一个分镜
        CrtDramaProjectStoryboard entity = new CrtDramaProjectStoryboard();
        entity.setUser_id(SecurityUtil.getUserId());
        entity.setDrama_project_id(drama_project_id);
        entity.setEpisode_num(episode_num);
        entity.setSort(1);
        crtDramaProjectStoryboardDao.insert(entity);

        Map<String, Object> resp = new LinkedHashMap<>();
        resp.put("drama_project_id", drama_project_id);
        resp.put("episode_num", episode_num);
        return resp;
    }

    /**
     * 删除分集
     */
    @Override
    public Map<String, Object> deleteStoryboard(CrtDramaProjectStoryboard crtDramaProjectStoryboard) {

        Long drama_project_id = crtDramaProjectStoryboard.getDrama_project_id();
        Integer episode_num = crtDramaProjectStoryboard.getEpisode_num();

        // [Event] 删除全部分镜
        eventDeleteStoryboard(drama_project_id, episode_num);

        Map<String, Object> resp = new LinkedHashMap<>();
        resp.put("drama_project_id", drama_project_id);
        resp.put("episode_num", episode_num);
        return resp;
    }

    /**
     * 删除单个分镜
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> deleteStoryboardBySort(CrtDramaProjectStoryboard crtDramaProjectStoryboard) {

        Long drama_project_storyboard_id = crtDramaProjectStoryboard.getDrama_project_storyboard_id();

        LambdaQueryWrapper<CrtDramaProjectStoryboard> wrapperStoryboard = new LambdaQueryWrapper<>();
        wrapperStoryboard.eq(CrtDramaProjectStoryboard::getDrama_project_storyboard_id, drama_project_storyboard_id);
        CrtDramaProjectStoryboard storyboardDetail = crtDramaProjectStoryboardDao.selectOne(wrapperStoryboard);
        if (storyboardDetail == null) throw new CustException("分镜不存在");

        // 是否 [分镜] 拥有者，权限：
        // - 编辑自己的 (需 36.2.6.1 权限)
        // - 编辑自己及他人的 (需要 36.2.6 权限或超级管理员)
        Boolean isOwner = storyboardDetail.getUser_id() == SecurityUtil.getUserId();
        if (isOwner && !securityUtil.hasPermissions(Arrays.asList("36.2.6", "36.2.6.1"), MatchType.OR)) {
            throw new CustException(SecurityEnum.NOAUTH);
        }
        if (!isOwner && !securityUtil.hasPermission("36.2.6")) {
            throw new CustException(SecurityEnum.NOAUTH);
        }
        // ---------------------------------------------------------------------------

        // [DB] 删除分镜
        crtDramaProjectStoryboardDao.deleteById(drama_project_storyboard_id);

        // [DB/OBJ] 删除分镜下的生图内容 (批量删除 cos/tos)
        deleteStoryboardImage(drama_project_storyboard_id);

        return Map.of("drama_project_storyboard_id", drama_project_storyboard_id);
    }

    /**
     * [DB/OBJ] 删除分镜下的生图内容 (批量删除 cos/tos)
     */
    private void deleteStoryboardImage(Long drama_project_storyboard_id) {
        LambdaQueryWrapper<CrtGenerateImage> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CrtGenerateImage::getDrama_project_storyboard_id, drama_project_storyboard_id);
        List<CrtGenerateImage> generateImageList = crtGenerateImageDao.selectList(wrapper);
        if (generateImageList != null && !generateImageList.isEmpty()) {

            // 获得生图内容的 object_keys
            List<ObjectKey> object_keys = new ArrayList<>();
            generateImageList.stream().forEach(item -> {
                ObjectKey objectKey = new ObjectKey();
                objectKey.setObject_key(item.getObject_key());
                objectKey.setTarget(item.getTarget());
                object_keys.add(objectKey);
            });

            CompletableFuture.runAsync(() -> {
                // 批量删除生图记录
                crtGenerateImageDao.delete(wrapper);
                // 批量删除 ObjectKeys (By target)
                objectKeyUtil.deleteObjects(object_keys);
            });

        }
    }

}
