package com.usky.ai.service;


import com.usky.ai.dto.*;
import com.usky.ai.service.listener.BoardPingListener;
import com.usky.ai.service.mqtt.MqttGateway;
import com.usky.ai.service.util.JsonUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import static com.usky.ai.service.listener.BoardPingListener.ReplyCache.*;

/**
 * 统一封装所有与盒子交互的 MQTT 请求
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class EdgeMediaService {

    private final MqttGateway gateway;

    private final RestTemplate restTemplate;

    @Value("${api.base-url}")
    private String baseUrl;

    @Value("${file.path}")
    private String filePath;

    @Value("${file.domain}")
    private String fileDomain;

    @Value("${file.prefix}")
    private String filePrefix;

    public EdgeAppControllerReplyDTO addChannel(EdgeAppControllerRequestDTO req) {
        req.setEvent("/alg_media_config");
        gateway.sendToMqtt("/edge_app_controller", 2, JsonUtils.toJson(req));
        return waitCache(REPLY, req.getBoardId() + "-" + req.getMediaName());
    }

    public EdgeAppFetchResponseDTO fetchChannels(String boardId) {
        EdgeAppControllerRequestDTO req = new EdgeAppControllerRequestDTO();
        req.setBoardId(boardId);
        req.setEvent("/alg_media_fetch");
        gateway.sendToMqtt("/edge_app_controller", 2, JsonUtils.toJson(req));
        log.info("【发送】查询通道请求：{}", JsonUtils.toJson(req));
        return waitCache(FETCH, boardId);
    }

    public EdgeAppDeleteResponseDTO deleteChannel(String boardId, String mediaName) {
        EdgeAppControllerRequestDTO req = new EdgeAppControllerRequestDTO();
        req.setBoardId(boardId);
        req.setEvent("/alg_media_delete");
        req.setMediaName(mediaName);
        gateway.sendToMqtt("/edge_app_controller", 2, JsonUtils.toJson(req));
        return waitCache(DELETE, boardId + "-" + mediaName);
    }

    public EdgeAlgTaskResponseDTO configTask(EdgeAlgTaskConfigRequestDTO req) {
        req.setEvent("/alg_task_config");
        gateway.sendToMqtt("/edge_app_controller", 2, JsonUtils.toJson(req));
        return waitCache(TASK, req.getBoardId() + "-" + req.getAlgTaskSession());
    }

    public EdgeAlgTaskResponseDTO controlTask(String boardId, String algTaskSession, int command) {
        EdgeAlgTaskCommandRequestDTO req = new EdgeAlgTaskCommandRequestDTO();
        req.setBoardId(boardId);
        req.setEvent("/alg_task_control");
        req.setControlCommand(command);
        req.setAlgTaskSession(algTaskSession);
        gateway.sendToMqtt("/edge_app_controller", 2, JsonUtils.toJson(req));
        return waitCache(TASK, boardId + "-" + algTaskSession);
    }

    public EdgeAlgTaskResponseDTO deleteTask(String boardId, String algTaskSession) {
        EdgeAlgTaskCommandRequestDTO req = new EdgeAlgTaskCommandRequestDTO();
        req.setBoardId(boardId);
        req.setEvent("/alg_task_delete");
        req.setAlgTaskSession(algTaskSession);
        gateway.sendToMqtt("/edge_app_controller", 2, JsonUtils.toJson(req));
        return waitCache(TASK, boardId + "-" + algTaskSession);
    }

    public EdgeAlgTaskListResponseDTO fetchTasks(String boardId) {
        EdgeAlgTaskFetchRequestDTO req = new EdgeAlgTaskFetchRequestDTO();
        req.setBoardId(boardId);
        req.setEvent("/alg_task_fetch");
        gateway.sendToMqtt("/edge_app_controller", 2, JsonUtils.toJson(req));
        return waitCache(ALG_TASK_LIST, boardId);
    }

    public AlgAbilityFetchResponseDTO fetchAlgorithmAbility(String boardId) {
        AlgAbilityFetchRequestDTO req = new AlgAbilityFetchRequestDTO();
        req.setBoardId(boardId);
        gateway.sendToMqtt("/edge_app_controller", 2, JsonUtils.toJson(req));
        return waitCache(BoardPingListener.ReplyCache.ALG_ABILITY, boardId + "-alg_ability_fetch");
    }


    public RepositoriesInfoResponseDTO listRepositories() {
        String url = baseUrl + "/api_repositories_info";
        ResponseEntity<RepositoriesInfoResponseDTO> response = restTemplate.getForEntity(url, RepositoriesInfoResponseDTO.class);
        if (response.getStatusCode().is2xxSuccessful()) {
            return response.getBody();
        } else {
            throw new RuntimeException("Failed to list repositories: " + response.getStatusCode());
        }
    }

    public RepositoryCreateResponseDTO createRepository(RepositoryCreateRequestDTO request) {
        String url = baseUrl + "/api_repository_create";
        ResponseEntity<RepositoryCreateResponseDTO> response = restTemplate.postForEntity(url, request, RepositoryCreateResponseDTO.class);
        if (response.getStatusCode().is2xxSuccessful()) {
            return response.getBody();
        } else {
            throw new RuntimeException("Failed to create repository: " + response.getStatusCode());
        }
    }

    public RepositoryUpdateResponseDTO updateRepository(RepositoryUpdateRequestDTO request) {
        String url = baseUrl + "/api_repository_update";
        ResponseEntity<RepositoryUpdateResponseDTO> response = restTemplate.postForEntity(url, request, RepositoryUpdateResponseDTO.class);
        if (response.getStatusCode().is2xxSuccessful()) {
            return response.getBody();
        } else {
            throw new RuntimeException("Failed to update repository: " + response.getStatusCode());
        }
    }

    public RepositoryDeleteResponseDTO deleteRepository(RepositoryDeleteRequestDTO request) {
        String url = baseUrl + "/api_repository_delete";
        ResponseEntity<RepositoryDeleteResponseDTO> response = restTemplate.postForEntity(url, request, RepositoryDeleteResponseDTO.class);
        if (response.getStatusCode().is2xxSuccessful()) {
            return response.getBody();
        } else {
            throw new RuntimeException("Failed to delete repository: " + response.getStatusCode());
        }
    }

    public RepositoryFacesResponseDTO getRepositoryFaces(RepositoryFacesRequestDTO request) {
        String url = baseUrl + "/api_repository_faces";
        ResponseEntity<RepositoryFacesResponseDTO> response = restTemplate.postForEntity(url, request, RepositoryFacesResponseDTO.class);
        if (response.getStatusCode().is2xxSuccessful()) {
            return response.getBody();
        } else {
            throw new RuntimeException("Failed to get repository faces: " + response.getStatusCode());
        }
    }

    public RegisterFaceResponseDTO registerFace(RegisterFaceRequestDTO request) {
        String url = baseUrl + "/api_register_face";
        ResponseEntity<RegisterFaceResponseDTO> response = restTemplate.postForEntity(url, request, RegisterFaceResponseDTO.class);
        if (response.getStatusCode().is2xxSuccessful()) {
            return response.getBody();
        } else {
            throw new RuntimeException("Failed to register face: " + response.getStatusCode());
        }
    }

    public UpdateFaceResponseDTO updateFace(UpdateFaceRequestDTO request) {
        String url = baseUrl + "/api_face_update";
        ResponseEntity<UpdateFaceResponseDTO> response = restTemplate.postForEntity(url, request, UpdateFaceResponseDTO.class);
        if (response.getStatusCode().is2xxSuccessful()) {
            return response.getBody();
        } else {
            throw new RuntimeException("Failed to update face: " + response.getStatusCode());
        }
    }

    public DeleteFaceResponseDTO deleteFace(DeleteFaceRequestDTO request) {
        String url = baseUrl + "/api_face_delete";
        ResponseEntity<DeleteFaceResponseDTO> response = restTemplate.postForEntity(url, request, DeleteFaceResponseDTO.class);
        if (response.getStatusCode().is2xxSuccessful()) {
            return response.getBody();
        } else {
            throw new RuntimeException("Failed to delete face: " + response.getStatusCode());
        }
    }

    public FaceRecognitionResponseDTO recognizeFace(FaceRecognitionRequestDTO request) {
        String url = baseUrl + "/api/faceengine/face/1vn";
        ResponseEntity<FaceRecognitionResponseDTO> response = restTemplate.postForEntity(url, request, FaceRecognitionResponseDTO.class);
        if (response.getStatusCode().is2xxSuccessful()) {
            return response.getBody();
        } else {
            throw new RuntimeException("Failed to recognize face: " + response.getStatusCode());
        }
    }

    public AlgTaskSnapResponseDTO getTaskPreview(String boardId, String algTaskSession) {
        AlgTaskSnapRequestDTO req = new AlgTaskSnapRequestDTO();
        req.setBoardId(boardId);
        req.setAlgTaskSession(algTaskSession);

        gateway.sendToMqtt("/edge_app_controller", 2, JsonUtils.toJson(req));
        return waitCache(BoardPingListener.ReplyCache.TASK_PREVIEW, boardId + "-" + algTaskSession);
    }

    public AlgScheduleCreateResponseDTO createSchedule(AlgScheduleCreateRequestDTO req) {
        req.setEvent("/alg_schedule_create");
        req.convertTimePeriodsToBinary(); // 转换时间段为二进制数据
        gateway.sendToMqtt("/edge_app_controller", 2, JsonUtils.toJson(req));
        return waitCache(BoardPingListener.ReplyCache.SCHEDULE_CREATE, req.getBoardId() + "-schedule-create");
    }

    public AlgScheduleFetchResponseDTO fetchSchedules(String boardId) {
        AlgScheduleFetchRequestDTO req = new AlgScheduleFetchRequestDTO();
        req.setBoardId(boardId);
        gateway.sendToMqtt("/edge_app_controller", 2, JsonUtils.toJson(req));
        return waitCache(BoardPingListener.ReplyCache.SCHEDULE_FETCH, boardId + "-schedule-fetch");
    }

    public AlgScheduleDeleteResponseDTO deleteSchedule(String boardId, Long id) {
        AlgScheduleDeleteRequestDTO req = new AlgScheduleDeleteRequestDTO();
        req.setBoardId(boardId);
        req.setId(id);
        gateway.sendToMqtt("/edge_app_controller", 2, JsonUtils.toJson(req));
        return waitCache(BoardPingListener.ReplyCache.SCHEDULE_DELETE, boardId + "-schedule-delete-" + id);
    }

    public AlgSuitCreateResponseDTO createSuitGroup(AlgSuitCreateRequestDTO req) {
        log.info("收到创建工装组请求：{}", req);
        gateway.sendToMqtt("/edge_app_controller", 2, JsonUtils.toJson(req));
        return waitCache(BoardPingListener.ReplyCache.SUIT_CREATE, req.getBoardId() + "-suit-create");
    }

    public AlgSuitGroupRemoveResponseDTO removeSuitGroup(AlgSuitGroupRemoveRequestDTO req) {
        gateway.sendToMqtt("/edge_app_controller", 2, JsonUtils.toJson(req));
        return waitCache(BoardPingListener.ReplyCache.SUIT_REMOVE, req.getBoardId() + "-suit-remove");
    }

    public AlgSuitAppendResponseDTO appendSuitTemplate(AlgSuitAppendRequestDTO req) {
        gateway.sendToMqtt("/edge_app_controller", 2, JsonUtils.toJson(req));
        return waitCache(BoardPingListener.ReplyCache.SUIT_APPEND, req.getBoardId() + "-suit-append");
    }

    public AlgSuitRemoveResponseDTO removeSuitTemplate(AlgSuitRemoveRequestDTO req) {
        gateway.sendToMqtt("/edge_app_controller", 2, JsonUtils.toJson(req));
        return waitCache(BoardPingListener.ReplyCache.SUIT_REMOVE_TEMPLATE, req.getBoardId() + "-suit-remove-template");
    }

    public AlgSuitFetchResponseDTO fetchSuitGroup(String boardId) {
        AlgSuitFetchRequestDTO req = new AlgSuitFetchRequestDTO();
        req.setBoardId(boardId);
        gateway.sendToMqtt("/edge_app_controller", 2, JsonUtils.toJson(req));
        return waitCache(BoardPingListener.ReplyCache.SUIT_FETCH, boardId + "-suit-fetch");
    }

    public String getTaskPreviewUrl(String boardId, String algTaskSession) {
        AlgTaskSnapResponseDTO response = getTaskPreview(boardId, algTaskSession);
        if (response.isSuccess() && response.getBase64() != null) {
            try {
                return saveImage(response.getBase64(), "taskPreview");
            } catch (IOException e) {
                log.error("Failed to save task preview image", e);
                throw new RuntimeException("Failed to save task preview image", e);
            }
        } else {
            throw new RuntimeException("Failed to get task preview: " + response.getResult().getDesc());
        }
    }

    private String saveImage(String base64Image, String fileName) throws IOException {
        // 检查 Base64 数据是否符合预期格式
        byte[] imageBytes = Base64Utils.decodeFromString(base64Image);

        // 生成文件路径 (使用yyyyMMddHHmmss格式)
        LocalDateTime now = LocalDateTime.now();
        String monthPath = now.format(DateTimeFormatter.ofPattern("yyyyMM"));
        String formattedTime = now.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
        int counterSuffix = new AtomicInteger(0).getAndIncrement(); // 获取并递增计数器
        String filePathWithPrefix = filePath + "/" + monthPath + "/" + fileName + "_" + formattedTime + "_" + counterSuffix + ".jpg";
        Path path = Paths.get(filePathWithPrefix);

        // 保存图片到文件系统
        Files.createDirectories(path.getParent());
        Files.write(path, imageBytes);

        // 返回可访问的 URL
        return fileDomain + filePrefix + "/" + monthPath + "/" + fileName + "_" + formattedTime + "_" + counterSuffix + ".jpg";
    }

    private <T> T waitCache(Map<String, T> cache, String key) {
        for (int i = 0; i < 50; i++) {
            T resp = cache.get(key);
            if (resp == null) {
                try {
                    TimeUnit.MILLISECONDS.sleep(100);
                } catch (InterruptedException ignored) {
                }
                continue;
            }

            if (resp instanceof EdgeAppControllerReplyDTO) {
                EdgeAppControllerReplyDTO reply = (EdgeAppControllerReplyDTO) resp;
                if (!reply.isSuccess()) {
                    cache.remove(key);
                    throw new RuntimeException(reply.getResult().getDesc());
                }
            }

            if (resp instanceof AlgAbilityFetchResponseDTO) {
                AlgAbilityFetchResponseDTO reply = (AlgAbilityFetchResponseDTO) resp;
                if (!reply.isSuccess()) {
                    cache.remove(key);
                    throw new RuntimeException(reply.getResult().getDesc());
                }
            }

            cache.remove(key);
            return resp;
        }
        throw new RuntimeException("等待盒子响应超时");
    }
}