package cn.iocoder.yudao.module.pms.hik;

import cn.iocoder.yudao.module.pms.controller.admin.alarm.vo.IotVideoAlarmSaveReqVO;
import cn.iocoder.yudao.module.pms.service.alarm.IotVideoAlarmService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.QName;
import org.dom4j.io.SAXReader;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.StringReader;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

@Slf4j
@Service
@RequiredArgsConstructor
public class HikIsapiService {
    
    private final HikHttpClient httpClient;
    private final HikvisionProperties properties;
    private final ObjectMapper objectMapper = new ObjectMapper();
    private final AlarmEventService alarmEventService;
    
    /**
     * 订阅事件通知
     */
    public String subscribeEvents(String deviceId) throws IOException {
        HikvisionProperties.IsapiConfig.DeviceConfig device = getDeviceConfig(deviceId);
        String url = device.getBaseUrl() + device.getPaths().getEventNotification();
        
        // 构建JSON订阅请求
        Map<String, Object> subscribeRequest = buildSubscribeRequest(deviceId);
        String jsonRequest = objectMapper.writeValueAsString(subscribeRequest);
        
        log.info("订阅事件通知: deviceId={}, url={}", deviceId, url);
        
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");
        
        String response = httpClient.doPost(url, jsonRequest, 
            device.getUsername(), device.getPassword(), 
            device.getTimeout(), headers);
        
        log.info("订阅成功: deviceId={}, response={}", deviceId, response);
        return response;
    }

    /**
     * 获取sip信息
     * @param deviceId
     * @return
     * @throws IOException
     */
    public String getSipInfo(String deviceId) throws IOException {
        HikvisionProperties.IsapiConfig.DeviceConfig device = getDeviceConfig(deviceId);
        String url = device.getBaseUrl() + device.getPaths().getSipInfo();

        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");

        String response = httpClient.doGet(url, device.getUsername(), device.getPassword(),
                device.getTimeout(), headers);
        return response;
    }

    /**
     * 获取图片
     * @param deviceId
     * @return
     * @throws IOException
     */
    public byte[] getPicInfo(String deviceId, String url) throws IOException {
        HikvisionProperties.IsapiConfig.DeviceConfig device = getDeviceConfig(deviceId);

        Map<String, String> headers = new HashMap<>();
        // 注意：图片接口不需要Content-Type为application/json，这是错误的，建议删除或修改
        // headers.put("Content-Type", "application/json");
        // 正确的请求头应该适配图片类型
        headers.put("Accept", "image/jpeg,image/png");

        // 调用httpClient的doGet方法获取String响应
        byte[] response = httpClient.doGetByte(url, device.getUsername(), device.getPassword(),
                device.getTimeout(), headers);

        // 核心：将String转换为byte[]（指定编码，推荐UTF-8）
        // ！！重要提醒：如果response是图片二进制的字符乱码，转换后也无法恢复！！
//        byte[] resultBytes = response.getBytes();

        return response;

//        Map<String, String> headers = new HashMap<>();
//        headers.put("Content-Type", "application/json");
//
//        String response = httpClient.doGet(url, device.getUsername(), device.getPassword(),
//                device.getTimeout(), headers);
//        return response;
    }

    /**
     * 构建订阅JSON
     */
    private Map<String, Object> buildSubscribeRequest(String deviceId) {
        Map<String, Object> request = new HashMap<>();
        request.put("method", "Event.notification");
        request.put("id", UUID.randomUUID().toString());
        
        Map<String, Object> params = new HashMap<>();
        params.put("protocol", "json");
        
        // 回调地址配置
        HikvisionProperties.IsapiConfig.CallbackConfig callback = 
            properties.getIsapi().getCallback();
        
        if (callback != null && callback.getEnabled()) {
            Map<String, Object> httpHost = new HashMap<>();
            httpHost.put("url", callback.getLocalUrl());
            httpHost.put("method", "POST");
            httpHost.put("timeout", 10);
            httpHost.put("contentType", "application/json");
            
            Map<String, Object> notification = new HashMap<>();
            notification.put("httpHost", httpHost);
            notification.put("heartbeatInterval", 
                properties.getIsapi().getDevices().stream()
                    .filter(d -> d.getId().equals(deviceId))
                    .findFirst()
                    .map(d -> d.getSubscription().getHeartbeatInterval())
                    .orElse(30));
            
            params.put("notification", notification);
        }
        
        request.put("params", params);
        return request;
    }
    
    /**
     * 取消订阅
     */
    public String unsubscribeEvents(String deviceId) throws IOException {
        HikvisionProperties.IsapiConfig.DeviceConfig device = getDeviceConfig(deviceId);
        String url = device.getBaseUrl() + device.getPaths().getEventNotification();
        
        Map<String, Object> unsubscribeRequest = new HashMap<>();
        unsubscribeRequest.put("method", "Event.unsubscribe");
        unsubscribeRequest.put("id", UUID.randomUUID().toString());
        
        String jsonRequest = objectMapper.writeValueAsString(unsubscribeRequest);
        
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");
        
        return httpClient.doPost(url, jsonRequest, 
            device.getUsername(), device.getPassword(), 
            device.getTimeout(), headers);
    }
    
    /**
     * 获取设备信息
     */
    public String getDeviceInfo(String deviceId) throws IOException {
        HikvisionProperties.IsapiConfig.DeviceConfig device = getDeviceConfig(deviceId);
        String url = device.getBaseUrl() + device.getPaths().getDeviceInfo();
        
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");
        
        return httpClient.doGet(url, 
            device.getUsername(), device.getPassword(), 
            device.getTimeout(), headers);
    }

    private final IotVideoAlarmService iotVideoAlarmService;
    /**
     * 处理告警回调
     */
    public void handleAlarmCallback(String jsonPayload) {
        try {
            log.info("收到告警回调: {}", jsonPayload);
            // 解析JSON
            IotVideoAlarmSaveReqVO alarmEvent = objectMapper.readValue(
                jsonPayload, IotVideoAlarmSaveReqVO.class);
            //安全帽检测与抽烟打电话
            if ("safetyHelmetDetection".equals(alarmEvent.getEventType()) || "抽烟打电话".equals(alarmEvent.getMpName())) {
                //调用sip获取是哪个业务通道
                String sipInfo = getSipInfo("nvr-001");
                List<VideoInput> videoInputs = parseVideoInputList(sipInfo);
                AtomicReference<String> businessChannelId = new AtomicReference<>();
                videoInputs.stream().filter(e -> String.valueOf(e.getId()).equals(alarmEvent.getChannelId())).findFirst().ifPresent(e -> {
                    businessChannelId.set(e.getVideoInputID());
                });
                if (businessChannelId.get() != null) {
                    alarmEvent.setBusinessChannel(businessChannelId.get());
                }
                // 保存到数据库
                iotVideoAlarmService.createIotVideoAlarm(alarmEvent);
                // 触发告警处理流程
                alarmEventService.processAlarmEvent(alarmEvent);
            }
        } catch (Exception e) {
            log.error("JSON解析失败: {}", jsonPayload, e);
            throw new RuntimeException("JSON解析失败", e);
        }
    }

    private HikvisionProperties.IsapiConfig.DeviceConfig getDeviceConfig(String deviceId) {
        return properties.getIsapi().getDevices().stream()
            .filter(d -> d.getId().equals(deviceId))
            .findFirst()
            .orElseThrow(() -> new IllegalArgumentException("设备不存在: " + deviceId));
    }

    private List<VideoInput> parseVideoInputList(String xmlStr) {
        List<VideoInput> videoInputList = new ArrayList<>();
        SAXReader reader = new SAXReader();

        try {
            // 读取 XML 字符串为 Document 对象
            Document document = reader.read(new StringReader(xmlStr));
            // 获取根节点（SIPInfo）
            Element root = document.getRootElement();

            // 1. 找到 VideoInputList 节点（带命名空间）
            Element videoInputListElement = root.element(QName.get("VideoInputList", "http://www.isapi.org/ver20/XMLSchema"));
            if (videoInputListElement == null) {
                return videoInputList;
            }

            // 2. 遍历所有 VideoInput 子节点
            Iterator<Element> videoInputIter = videoInputListElement.elementIterator(QName.get("VideoInput", "http://www.isapi.org/ver20/XMLSchema"));
            while (videoInputIter.hasNext()) {
                Element videoInputElement = videoInputIter.next();

                // 3. 提取 id 和 videoInputID
                Integer id = Integer.parseInt(videoInputElement.elementText(QName.get("id", "http://www.isapi.org/ver20/XMLSchema")));
                // 空标签（<videoInputID/>）会返回空字符串，需处理
                String videoInputID = videoInputElement.elementText(QName.get("videoInputID", "http://www.isapi.org/ver20/XMLSchema")).trim();

                // 4. 封装为 VideoInput 对象（可直接用 Map 替代，无需实体类）
                VideoInput input = new VideoInput();
                input.setId(id);
                input.setVideoInputID(videoInputID.isEmpty() ? null : videoInputID);

                videoInputList.add(input);
            }
        } catch (Exception e) {
            throw new RuntimeException("XML解析失败：" + e.getMessage(), e);
        }
        return videoInputList;
    }
    @Data
    public static class VideoInput {
        private Integer id;
        private String videoInputID;
    }
}