package com.ai.da.service.impl;

import com.ai.da.common.config.exception.BusinessException;
import com.ai.da.common.constant.CommonConstant;
import com.ai.da.common.context.UserContext;
import com.ai.da.common.enums.CreditsEventsEnum;
import com.ai.da.common.response.PageBaseResponse;
import com.ai.da.common.utils.RedisUtil;
import com.ai.da.mapper.primary.TaskListMapper;
import com.ai.da.mapper.primary.entity.TaskList;
import com.ai.da.model.dto.QueryTaskHistoryDTO;
import com.ai.da.model.dto.SuperResolutionDTO;
import com.ai.da.model.dto.TaskDTO;
import com.ai.da.python.PythonService;
import com.ai.da.service.CreditsService;
import com.ai.da.service.RabbitMQService;
import com.ai.da.service.SuperResolutionService;
import com.ai.da.service.TaskListService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Slf4j
@Service
public class SuperResolutionServiceImpl extends ServiceImpl<TaskListMapper, TaskList> implements SuperResolutionService {

    public static final Integer creditsConsumption = 100;

    @Resource
    private CreditsService creditsService;
    @Resource
    private RabbitMQService rabbitMQService;
    @Resource
    private PythonService pythonService;

    @Resource
    private TaskListService taskListService;

    @Resource
    private RedisUtil redisUtil;

    @Value("${redis.key.orderForSR}")
    private String orderForSR;

    @Value("${minio.bucketName.users}")
    private String usersBucket;

    @Value("${minio.endpoint}")
    private String endpoint;

    @Value("${redis.key.credits.pre-deduction}")
    private String creditsDeduction;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<String> prepareForSR(List<SuperResolutionDTO> superResolutionDTOList) {

        Long accountId = UserContext.getUserHolder().getId();
        // 1、判断用户当前积分是否够本次超分消耗
        Boolean preDeduction = creditsService.creditsPreDeduction(CreditsEventsEnum.SUPER_RESOLUTION, superResolutionDTOList.size());
        if (!preDeduction) {
            throw new BusinessException("Not enough Credits");
        }

        ArrayList<String> uuidList = new ArrayList<>();
        for (SuperResolutionDTO superResolutionDTO : superResolutionDTOList) {

            // 2、生成唯一id 使用uuid 由于uuid重复的几率很小很小，故这里取消验证uuid是否已存在
            String uuid = UUID.randomUUID().toString();
            uuid += "-" + accountId;
            uuidList.add(uuid);

            // 3、截取minio地址 (前提是该url是由minio地址转换来的)
            String inputString = superResolutionDTO.getImages();
            String replace = inputString.replace(endpoint + "/", "");
            String minioPath = replace.substring(0, replace.indexOf("?"));
//            log.info(minioPath);
            superResolutionDTO.setImages(minioPath);

            superResolutionDTO.setUniqueId(uuid);
            String jsonString = JSON.toJSONString(superResolutionDTO);

            // 4、将数据存到数据库
            TaskList taskList = new TaskList();
            taskList.setAccountId(accountId);
            taskList.setTaskType("SR");
            taskList.setInputUrl(superResolutionDTO.getImages());
            taskList.setScale(superResolutionDTO.getScale());
            taskList.setStatus("Waiting");
            taskList.setTaskId(superResolutionDTO.getUniqueId());
            taskList.setCreateTime(LocalDateTime.now());

            baseMapper.insert(taskList);

            // 5、添加当前任务的预扣积分到redis 任务有效期一天，若待扣积分两天还没被移除，说明任务已经失败，待扣积分自动失效
            creditsService.addRecordToCreditsDeduction(accountId, uuid, CreditsEventsEnum.SUPER_RESOLUTION);
//            redisUtil.addToString(creditsDeduction + ":" + accountId + ":" + uuid, CreditsEventsEnum.SUPER_RESOLUTION.getValue(), CommonConstant.CREDITS_EXPIRE_TIME);

            // 6、加入任务列表 设置状态为 等待中
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            String name = superResolutionDTO.getImages();
            taskListService.addToTaskListRedis(new TaskDTO<>(uuid, "SR", name.substring(name.lastIndexOf("/") + 1), superResolutionDTO, "Waiting", LocalDateTime.now().format(dateTimeFormatter)));

            // 7、将消息发布到MQ消息队列
            log.info("发送消息到SR_QUEUE，参数 ：{}", jsonString);
            rabbitMQService.publishMessageToSR(jsonString);
        }

        // 8、返回唯一id列表
        return uuidList;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void SR(SuperResolutionDTO superResolutionDTO) throws Exception {
        // 1、向模型发起请求
        pythonService.superResolution(superResolutionDTO);

        // 2、更新状态
        updateSROutput(superResolutionDTO.getUniqueId(), "Executing", null);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void setSRResult(String taskId, String output, String status) {
        Long accountId = Long.parseLong(taskId.substring(taskId.lastIndexOf("-") + 1));
        // 获取结果后更新
        updateSROutput(taskId, status, output);

        if ("success".equals(status)) {
            // 3、扣除积分
            creditsService.taskCreditsDeduction(accountId, taskId);
            // 4、记录积分变更
            creditsService.insertToCreditsDetail(accountId,
                    CreditsEventsEnum.SUPER_RESOLUTION.getName(),
                    CreditsEventsEnum.SUPER_RESOLUTION.getValue(),
                    "negative", null);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSROutput(String taskId, String status, String output) {
        UpdateWrapper<TaskList> uw = new UpdateWrapper<>();
        uw.eq("task_id", taskId);

        uw.set("output_url", output);
        uw.set("status", status);
        baseMapper.update(null, uw);

    }

    // 分页查询
    @Override
    public PageBaseResponse<TaskList> getTaskHistoryPage(QueryTaskHistoryDTO queryTaskHistoryDTO) {
        QueryWrapper<TaskList> qw = new QueryWrapper<>();
        qw.eq("account_id", UserContext.getUserHolder().getId());

        String startTime = queryTaskHistoryDTO.getStartTime();
        String endTime = queryTaskHistoryDTO.getEndTime();
        if (StringUtil.isNullOrEmpty(startTime)) {
            startTime = "2024-03-01 00:00:00";
        }
        if (StringUtil.isNullOrEmpty(endTime)) {
            LocalDateTime now = LocalDateTime.now();
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            endTime = now.format(dateTimeFormatter);
        }

        qw.between("create_time", startTime, endTime);
        qw.orderByDesc("create_time");
        Page<TaskList> pageInfo = new Page<>(queryTaskHistoryDTO.getPage(), queryTaskHistoryDTO.getSize());
        Page<TaskList> orderInfo = baseMapper.selectPage(pageInfo, qw);
        if (CollectionUtils.isEmpty(orderInfo.getRecords())) {
            return PageBaseResponse.success(new Page<>());
        }

        return PageBaseResponse.success(orderInfo);
    }
}
