package com.ycwl.basic.service.mobile;

import com.ycwl.basic.device.DeviceFactory;
import com.ycwl.basic.device.entity.common.FileObject;
import com.ycwl.basic.device.operator.IDeviceStorageOperator;
import com.ycwl.basic.integration.device.dto.device.DeviceV2DTO;
import com.ycwl.basic.integration.device.service.DeviceIntegrationService;
import com.ycwl.basic.model.mobile.video.dto.HlsStreamRequest;
import com.ycwl.basic.model.mobile.video.dto.HlsStreamResponse;
import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
import com.ycwl.basic.repository.DeviceRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * HLS视频流服务
 * 用于生成设备视频的HLS播放列表(m3u8)
 *
 * @author Claude Code
 * @date 2025-12-26
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class HlsStreamService {

    private final DeviceIntegrationService deviceIntegrationService;
    private final DeviceRepository deviceRepository;

    private static final String M3U8_HEADER = "#EXTM3U";
    private static final String M3U8_VERSION = "#EXT-X-VERSION:3";
    private static final String M3U8_MEDIA_SEQUENCE = "#EXT-X-MEDIA-SEQUENCE:0";
    private static final String M3U8_ALLOW_CACHE = "#EXT-X-ALLOW-CACHE:YES";
    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 生成设备视频的HLS播放列表
     *
     * @param request HLS流请求参数
     * @return HLS播放列表响应
     */
    public HlsStreamResponse generateHlsPlaylist(HlsStreamRequest request) {
        log.info("开始生成HLS播放列表: deviceId={}, durationMinutes={}",
                request.getDeviceId(), request.getDurationMinutes());

        try {
            // 获取设备信息
            DeviceV2DTO device = deviceIntegrationService.getDevice(request.getDeviceId());
            if (device == null) {
                throw new RuntimeException("设备不存在: " + request.getDeviceId());
            }

            // 获取设备配置
            DeviceConfigEntity config = deviceRepository.getDeviceConfig(request.getDeviceId());
            if (config == null) {
                throw new RuntimeException("设备配置不存在: " + request.getDeviceId());
            }

            // 获取设备的存储操作器
            IDeviceStorageOperator operator = DeviceFactory.getDeviceStorageOperator(device, config);
            if (operator == null) {
                throw new RuntimeException("设备未配置存储操作器: " + request.getDeviceId());
            }

            // 计算时间范围：当前时间向前N分钟
            Calendar calendar = Calendar.getInstance();
            Date endDate = calendar.getTime();
            calendar.add(Calendar.MINUTE, -request.getDurationMinutes());
            Date startDate = calendar.getTime();

            log.info("查询视频文件范围: deviceId={}, startDate={}, endDate={}",
                    request.getDeviceId(), DATE_FORMAT.format(startDate), DATE_FORMAT.format(endDate));

            // 获取视频文件列表
            List<FileObject> fileList = operator.getFileListByDtRange(startDate, endDate);
            if (fileList == null || fileList.isEmpty()) {
                log.warn("未找到视频文件: deviceId={}, startDate={}, endDate={}",
                        request.getDeviceId(), DATE_FORMAT.format(startDate), DATE_FORMAT.format(endDate));
                return buildEmptyResponse(request.getDeviceId(), request.getEventPlaylist());
            }

            // 按创建时间排序（升序）
            fileList.sort(Comparator.comparing(FileObject::getCreateTime));

            log.info("找到 {} 个视频文件", fileList.size());

            // 生成播放列表
            return buildHlsResponse(request.getDeviceId(), fileList, request.getEventPlaylist());

        } catch (Exception e) {
            log.error("生成HLS播放列表失败: deviceId={}", request.getDeviceId(), e);
            throw new RuntimeException("生成HLS播放列表失败: " + e.getMessage(), e);
        }
    }

    /**
     * 构建HLS响应
     *
     * @param deviceId 设备ID
     * @param fileList 视频文件列表
     * @param isEventPlaylist 是否为Event播放列表
     * @return HLS响应
     */
    private HlsStreamResponse buildHlsResponse(Long deviceId, List<FileObject> fileList, Boolean isEventPlaylist) {
        StringBuilder m3u8Content = new StringBuilder();
        List<HlsStreamResponse.VideoSegment> segments = new ArrayList<>();

        // 添加m3u8头部
        m3u8Content.append(M3U8_HEADER).append("\n");
        m3u8Content.append(M3U8_VERSION).append("\n");

        // 设置播放列表类型
        String playlistType = Boolean.TRUE.equals(isEventPlaylist) ? "EVENT" : "VOD";
        m3u8Content.append("#EXT-X-PLAYLIST-TYPE:").append(playlistType).append("\n");

        // 计算目标时长（使用视频片段的平均时长）
        double avgDuration = calculateAverageDuration(fileList);
        int targetDuration = (int) Math.ceil(avgDuration);
        m3u8Content.append("#EXT-X-TARGETDURATION:").append(targetDuration).append("\n");

        m3u8Content.append(M3U8_MEDIA_SEQUENCE).append("\n");
        m3u8Content.append(M3U8_ALLOW_CACHE).append("\n");

        // 添加视频片段
        double totalDuration = 0.0;
        int sequence = 0;

        for (FileObject file : fileList) {
            // 计算片段时长（秒）
            double duration = calculateSegmentDuration(file);
            totalDuration += duration;

            // 添加片段信息到m3u8
            m3u8Content.append("#EXTINF:").append(String.format("%.3f", duration)).append(",\n");
            m3u8Content.append(file.getUrl().replace("-internal.aliyuncs.com", ".aliyuncs.com")).append("\n");

            // 记录片段信息
            HlsStreamResponse.VideoSegment segment = HlsStreamResponse.VideoSegment.builder()
                    .url(file.getUrl())
                    .duration(duration)
                    .sequence(sequence++)
                    .startTime(file.getCreateTime() != null ? DATE_FORMAT.format(file.getCreateTime()) : null)
                    .endTime(file.getEndTime() != null ? DATE_FORMAT.format(file.getEndTime()) : null)
                    .build();
            segments.add(segment);
        }

        // 添加结束标记（VOD类型需要）
        if (!"EVENT".equals(playlistType)) {
            m3u8Content.append("#EXT-X-ENDLIST\n");
        }

        return HlsStreamResponse.builder()
                .deviceId(deviceId)
                .playlistContent(m3u8Content.toString())
                .segmentCount(fileList.size())
                .totalDurationSeconds(totalDuration)
                .segments(segments)
                .playlistType(playlistType)
                .build();
    }

    /**
     * 构建空响应
     */
    private HlsStreamResponse buildEmptyResponse(Long deviceId, Boolean isEventPlaylist) {
        String playlistType = Boolean.TRUE.equals(isEventPlaylist) ? "EVENT" : "VOD";
        StringBuilder m3u8Content = new StringBuilder();

        m3u8Content.append(M3U8_HEADER).append("\n");
        m3u8Content.append(M3U8_VERSION).append("\n");
        m3u8Content.append("#EXT-X-PLAYLIST-TYPE:").append(playlistType).append("\n");
        m3u8Content.append("#EXT-X-TARGETDURATION:0\n");
        m3u8Content.append(M3U8_MEDIA_SEQUENCE).append("\n");

        if (!"EVENT".equals(playlistType)) {
            m3u8Content.append("#EXT-X-ENDLIST\n");
        }

        return HlsStreamResponse.builder()
                .deviceId(deviceId)
                .playlistContent(m3u8Content.toString())
                .segmentCount(0)
                .totalDurationSeconds(0.0)
                .segments(Collections.emptyList())
                .playlistType(playlistType)
                .build();
    }

    /**
     * 计算视频片段的平均时长（秒）
     */
    private double calculateAverageDuration(List<FileObject> fileList) {
        if (fileList == null || fileList.isEmpty()) {
            return 10.0; // 默认10秒
        }

        List<Double> durations = fileList.stream()
                .map(this::calculateSegmentDuration)
                .filter(d -> d > 0)
                .collect(Collectors.toList());

        if (durations.isEmpty()) {
            return 10.0; // 默认10秒
        }

        return durations.stream()
                .mapToDouble(Double::doubleValue)
                .average()
                .orElse(10.0);
    }

    /**
     * 计算单个视频片段的时长（秒）
     */
    private double calculateSegmentDuration(FileObject file) {
        if (file.getCreateTime() != null && file.getEndTime() != null) {
            long durationMs = file.getEndTime().getTime() - file.getCreateTime().getTime();
            if (durationMs > 0) {
                return durationMs / 1000.0;
            }
        }
        // 如果无法计算，返回默认值10秒
        return 10.0;
    }
}
