package com.ycwl.basic.repository;

import cn.hutool.core.date.DateUtil;
import com.ycwl.basic.biz.TemplateBiz;
import com.ycwl.basic.config.VideoUpdateConfig;
import com.ycwl.basic.mapper.TaskMapper;
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.resp.TaskRespVO;
import com.ycwl.basic.model.repository.TaskUpdateResult;
import com.ycwl.basic.utils.JacksonUtil;
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.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
@Component
public class VideoTaskRepository {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private TaskMapper taskMapper;

    public static final String TASK_CACHE_KEY = "task:byId:%s";
    @Autowired
    private TemplateRepository templateRepository;
    @Autowired
    private SourceRepository sourceRepository;
    @Autowired
    private TemplateBiz templateBiz;
    @Autowired
    private VideoUpdateConfig videoUpdateConfig;

    public TaskEntity getTaskById(Long taskId) {
        if (redisTemplate.hasKey(String.format(TASK_CACHE_KEY, taskId))) {
            return JacksonUtil.parseObject(redisTemplate.opsForValue().get(String.format(TASK_CACHE_KEY, taskId)), TaskEntity.class);
        } else {
            TaskEntity task = taskMapper.get(taskId);
            if (task != null && 1 == task.getStatus()) {
                redisTemplate.opsForValue().set(String.format(TASK_CACHE_KEY, taskId), JacksonUtil.toJSONString(task), 12, TimeUnit.HOURS);
            }
            return task;
        }
    }

    public void clearTaskCache(Long taskId) {
        redisTemplate.delete(String.format(TASK_CACHE_KEY, taskId));
    }

    public Integer getTaskDeviceNum(Long taskId) {
        TaskEntity task = getTaskById(taskId);
        if (task == null) {
            return 1;
        }
        Map<String, Object> paramJson = JacksonUtil.parseObject(task.getTaskParams(), Map.class);
        if (paramJson == null) {
            return 1;
        }
        List<String> deviceIds = new ArrayList<>();
        List<String> templatePlaceholder = templateRepository.getTemplatePlaceholder(task.getTemplateId());
        paramJson.entrySet().stream()
                .filter(entry -> StringUtils.isNumeric(entry.getKey()))
                .forEach(entry -> {
                    List<Object> jsonArray = JacksonUtil.parseArray(JacksonUtil.toJSONString(entry.getValue()), Object.class);
                    if (jsonArray != null && !jsonArray.isEmpty()) {
                        for (Object ignored : jsonArray) {
                            if (templatePlaceholder.contains(entry.getKey())) {
                                if (!deviceIds.contains(entry.getKey())) {
                                    deviceIds.add(entry.getKey());
                                }
                            }
                        }
                    }
                });
        return deviceIds.size();
    }

    public Integer getTaskLensNum(Long taskId) {
        TaskEntity task = getTaskById(taskId);
        if (task == null) {
            return 1;
        }
        Map<String, Object> paramJson = JacksonUtil.parseObject(task.getTaskParams(), Map.class);
        if (paramJson == null) {
            return 1;
        }
        AtomicInteger deviceCount = new AtomicInteger();
        paramJson.entrySet().stream()
                .filter(entry -> StringUtils.isNumeric(entry.getKey()))
                .forEach(entry -> {
                    List<Object> jsonArray = JacksonUtil.parseArray(JacksonUtil.toJSONString(entry.getValue()), Object.class);
                    if (jsonArray != null && !jsonArray.isEmpty()) {
                        for (Object ignored : jsonArray) {
                            deviceCount.getAndIncrement();
                        }
                    }
                });
        return deviceCount.get();
    }

    public Date getTaskShotDate(Long taskId) {
        TaskEntity task = getTaskById(taskId);
        if (task == null) {
            return null;
        }
        Date shotTime = task.getCreateTime();
        Map<String, Object> paramJson = JacksonUtil.parseObject(task.getTaskParams(), Map.class);
        if (paramJson != null) {
            Optional<String> any = paramJson.keySet().stream().filter(StringUtils::isNumeric).findAny();
            if (any.isPresent()) {
                @SuppressWarnings("unchecked")
                List<Map<String, Object>> jsonArray = (List<Map<String, Object>>) paramJson.get(any.get());
                if (jsonArray != null && !jsonArray.isEmpty()) {
                    Map<String, Object> jsonObject = jsonArray.get(0);
                    if (jsonObject.containsKey("createTime")) {
                        Object createTimeObj = jsonObject.get("createTime");
                        if (createTimeObj instanceof Number) {
                            shotTime = new Date(((Number) createTimeObj).longValue());
                        }
                    }
                }
            }
        }
        return shotTime;
    }

    /**
     * 检查任务是否可以更新
     * @param taskId 任务ID
     * @return 任务更新检查结果
     */
    public TaskUpdateResult checkTaskUpdate(Long taskId) {
        TaskUpdateResult result = new TaskUpdateResult();

        TaskEntity task = getTaskById(taskId);
        if (task == null) {
            log.error("任务不存在: taskId={}", taskId);
            result.setCanUpdate(false);
            return result;
        }

        try {
            Map<String, Object> originalTaskParams = JacksonUtil.parseObject(task.getTaskParams(), Map.class);
            if (originalTaskParams == null) {
                log.error("原始任务参数解析失败: taskId={}", taskId);
                result.setCanUpdate(false);
                return result;
            }

            int originalSegmentCount = calculateSegmentCount(originalTaskParams);
            result.setOriginalSegmentCount(originalSegmentCount);

            Map<String, List<SourceEntity>> currentTaskParams = sourceRepository.getTaskParams(task.getFaceId(), task.getTemplateId());
            if (currentTaskParams.isEmpty()) {
                log.info("当前没有可用的任务参数: faceId={}, templateId={}", task.getFaceId(), task.getTemplateId());
                result.setCanUpdate(false);
                result.setTotalSegmentCount(0);
                result.setNewSegmentCount(0);
                return result;
            }

            Map<String, List<SourceEntity>> filteredTaskParams = templateBiz.filterTaskParams(task.getTemplateId(), currentTaskParams);
            int currentSegmentCount = calculateSegmentCount(filteredTaskParams);
            result.setTotalSegmentCount(currentSegmentCount);

            boolean hasNewSegments = videoUpdateConfig.isDetectChangesAsNew()
                ? hasNewSegments(originalTaskParams, filteredTaskParams)
                : currentSegmentCount > originalSegmentCount;
            int newSegmentCount = Math.max(0, currentSegmentCount - originalSegmentCount);

            boolean canUpdate = hasNewSegments && newSegmentCount >= videoUpdateConfig.getMinNewSegmentCount();
            result.setCanUpdate(canUpdate);
            result.setNewSegmentCount(newSegmentCount);

            log.debug("任务更新检查完成: taskId={}, canUpdate={}, newSegmentCount={}, originalCount={}, currentCount={}",
                    taskId, result.isCanUpdate(), newSegmentCount, originalSegmentCount, currentSegmentCount);

        } catch (Exception e) {
            log.error("检查任务更新失败: taskId={}", taskId, e);
            result.setCanUpdate(false);
        }

        return result;
    }

    /**
     * 计算片段数量
     */
    private int calculateSegmentCount(Map<String, ?> taskParams) {
        if (taskParams == null || taskParams.isEmpty()) {
            return 0;
        }

        return taskParams.entrySet().stream()
            .filter(entry -> StringUtils.isNumeric(entry.getKey()))
            .mapToInt(entry -> {
                Object value = entry.getValue();
                if (value instanceof List) {
                    return ((List<?>) value).size();
                }
                return 0;
            })
            .sum();
    }

    /**
     * 检查是否有新片段
     */
    private boolean hasNewSegments(Map<String, ?> originalParams, Map<String, List<SourceEntity>> currentParams) {
        Set<String> originalFileSet = extractFileSet(originalParams);
        Set<String> currentFileSet = extractFileSetFromEntities(currentParams);

        return !currentFileSet.equals(originalFileSet);
    }

    private Set<String> extractFileSet(Map<String, ?> params) {
        Set<String> fileSet = new HashSet<>();
        params.entrySet().stream()
            .filter(entry -> StringUtils.isNumeric(entry.getKey()))
            .forEach(entry -> {
                Object value = entry.getValue();
                if (value instanceof List) {
                    ((List<?>) value).forEach(item -> {
                        if (item instanceof Map) {
                            Map<?, ?> itemMap = (Map<?, ?>) item;
                            Object fileName = itemMap.get("fileName");
                            if (fileName != null) {
                                fileSet.add(fileName.toString());
                            }
                        }
                    });
                }
            });
        return fileSet;
    }

    private Set<String> extractFileSetFromEntities(Map<String, List<SourceEntity>> params) {
        Set<String> fileSet = new HashSet<>();
        params.values().forEach(entities ->
            entities.forEach(entity -> fileSet.add(entity.getVideoUrl()))
        );
        return fileSet;
    }
}
