package com.ycwl.basic.device.operator;

import cn.hutool.core.date.DateUtil;
import com.ycwl.basic.utils.JacksonUtil;
import com.ycwl.basic.device.entity.common.FileObject;
import com.ycwl.basic.device.entity.common.VideoContinuityGap;
import com.ycwl.basic.device.entity.common.VideoContinuityResult;
import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.entity.AliOssStorageConfig;
import com.ycwl.basic.storage.entity.StorageFileObject;
import com.ycwl.basic.storage.enums.StorageType;
import lombok.extern.slf4j.Slf4j;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
public class AliOssStorageOperator extends ADeviceStorageOperator {
    private IStorageAdapter adapter;

    public AliOssStorageOperator(String configJson) {
        loadConfig(configJson);
    }

    @Override
    public void loadConfig(String configJson) {
        AliOssStorageConfig config = JacksonUtil.parseObject(configJson, AliOssStorageConfig.class);
        adapter = StorageFactory.get(StorageType.ALI_OSS, config);
    }


    private List<StorageFileObject> getOssObjectListByPrefix(String prefix) {
        return adapter.listDir(prefix);
    }

    private List<FileObject> getOssFileListByPrefix(String prefix) {
        List<StorageFileObject> objectList = getOssObjectListByPrefix(prefix);
        if (objectList == null) {
            return null;
        }
        return objectList.stream().filter(item -> item.getName().endsWith(".ts")).map(item -> {
            FileObject object = new FileObject();
            object.setPath(item.getPath());
            object.setUrl(adapter.getUrlForDownload(item.getFullPath()));
            object.setNeedDownload(true);
            String[] splitDir = item.getPath().split("/");
            String splitDate = splitDir[splitDir.length - 1];
            String[] splitExt = item.getName().split("\\.", 2);
            String[] splitDt = splitExt[0].split("_", 2);
            String createTime = splitDt[0];
            String endTime = splitDt[1];
            object.setName(item.getName());
            object.setEndTime(DateUtil.parse(splitDate+endTime, "yyyyMMddHHmmss"));
            object.setCreateTime(DateUtil.parse(splitDate+createTime, "yyyyMMddHHmmss"));
            return object;
        }).collect(Collectors.toList());
    }

    private boolean removeFilesByPrefix(String prefix) {
        return adapter.deleteDir(prefix);
    }

    @Override
    public List<FileObject> getFileListByDtRange(Date startDate, Date endDate) {
        if (startDate == null || endDate == null) {
            return null;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startDate);
        calendar.set(Calendar.SECOND, 0);
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        String prefix = dateFormat.format(calendar.getTime());
        List<FileObject> fileList = getOssFileListByPrefix(prefix);
        if (fileList == null) {
            return null;
        }
        calendar.clear();
        return fileList.stream()
                .sorted(Comparator.comparing(FileObject::getCreateTime))
                .filter(item -> item.getEndTime().after(startDate))
                .filter(item -> item.getCreateTime().before(endDate))
                .collect(Collectors.toList());
    }

    @Override
    public boolean removeFilesBeforeDate(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd/");
        calendar.add(Calendar.DAY_OF_MONTH, -1);
        String prefix = dateFormat.format(calendar.getTime());
        return removeFilesByPrefix(prefix);
    }

    /**
     * 检查视频片段的连续性
     *
     * @param startDate 开始时间
     * @param endDate 结束时间
     * @param maxGapMs 允许的最大间隔时间(毫秒)
     * @return 包含缺口信息的验证结果
     */
    @Override
    public VideoContinuityResult checkVideoContinuity(Date startDate, Date endDate, long maxGapMs) {
        VideoContinuityResult result = new VideoContinuityResult();
        result.setSupport(true);
        result.setMaxAllowedGapMs(maxGapMs);

        // 获取时间范围内的视频列表
        List<FileObject> fileList = getFileListByDtRange(startDate, endDate);

        if (fileList == null || fileList.isEmpty()) {
            result.setContinuous(false);
            result.setTotalVideos(0);
            result.setTotalDurationMs(0);
            log.warn("未找到指定时间范围内的视频文件: {} - {}", startDate, endDate);
            return result;
        }

        result.setTotalVideos(fileList.size());

        // 只有一个视频文件时,认为是连续的
        if (fileList.size() == 1) {
            FileObject file = fileList.get(0);
            long duration = file.getEndTime().getTime() - file.getCreateTime().getTime();
            result.setContinuous(true);
            result.setTotalDurationMs(duration);
            return result;
        }

        // 检查相邻视频之间的间隙
        long totalDuration = 0;
        for (int i = 0; i < fileList.size() - 1; i++) {
            FileObject currentFile = fileList.get(i);
            FileObject nextFile = fileList.get(i + 1);

            // 计算当前视频的时长
            totalDuration += currentFile.getEndTime().getTime() - currentFile.getCreateTime().getTime();

            // 计算间隙: 后一个视频的开始时间 - 前一个视频的结束时间
            long gapMs = nextFile.getCreateTime().getTime() - currentFile.getEndTime().getTime();

            // 如果间隙超过允许值,记录该间隙
            if (gapMs > maxGapMs) {
                VideoContinuityGap gap = new VideoContinuityGap();
                gap.setBeforeFile(currentFile);
                gap.setAfterFile(nextFile);
                gap.setGapMs(gapMs);
                gap.setGapStartTime(currentFile.getEndTime());
                gap.setGapEndTime(nextFile.getCreateTime());
                result.addGap(gap);
                log.debug("检测到视频间隙: {} -> {}, 间隙时长: {}ms",
                    currentFile.getName(), nextFile.getName(), gapMs);
            }
        }

        // 加上最后一个视频的时长
        FileObject lastFile = fileList.get(fileList.size() - 1);
        totalDuration += lastFile.getEndTime().getTime() - lastFile.getCreateTime().getTime();

        result.setTotalDurationMs(totalDuration);
        result.setContinuous(result.getGapCount() == 0);

        log.info("视频连续性检查完成: 总视频数={}, 总时长={}ms, 间隙数={}, 连续={}",
            result.getTotalVideos(), result.getTotalDurationMs(), result.getGapCount(), result.isContinuous());

        return result;
    }

    /**
     * 检查近期视频的连续性(测试用)
     * 时间范围: 当前时间向前2分钟后,再向前10分钟(即前12分钟到前2分钟)
     * 允许的最大间隙: 2秒
     *
     * @return 包含缺口信息的验证结果
     */
    @Override
    public VideoContinuityResult checkRecentVideoContinuity() {
        Calendar calendar = Calendar.getInstance();

        // 结束时间: 当前时间 - 2分钟
        calendar.add(Calendar.MINUTE, -2);
        Date endDate = calendar.getTime();

        // 开始时间: 当前时间 - 12分钟 (再向前10分钟)
        calendar.add(Calendar.MINUTE, -10);
        Date startDate = calendar.getTime();

        log.info("检查近期视频连续性: {} - {}", startDate, endDate);

        // 允许的最大间隙为2秒(2000毫秒)
        return checkVideoContinuity(startDate, endDate, 2000L);
    }
}
