package com.ecep.contract.service.tasker;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledExecutorService;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Service;

import com.ecep.contract.Message;
import com.ecep.contract.constant.WebSocketConstant;
import com.ecep.contract.handler.SessionInfo;
import com.ecep.contract.model.Voable;
import com.ecep.contract.ui.Tasker;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

@Service
public class WebSocketServerTaskManager implements InitializingBean {
    private static final Logger logger = LoggerFactory.getLogger(WebSocketServerTaskManager.class);
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private ScheduledExecutorService scheduledExecutorService;
    @Autowired
    private ResourceLoader resourceLoader;
    private Map<String, String> taskClzMap = Map.of();

    @Override
    public void afterPropertiesSet() throws Exception {
        // 从tasker_mapper.json文件中加载任务注册信息
        try {
            Resource resource = resourceLoader.getResource("classpath:tasker_mapper.json");
            try (InputStream inputStream = resource.getInputStream()) {
                JsonNode rootNode = objectMapper.readTree(inputStream);
                JsonNode tasksNode = rootNode.get("tasks");
                if (tasksNode != null && tasksNode.isObject()) {
                    Map<String, String> taskMap = new java.util.HashMap<>();
                    tasksNode.fields().forEachRemaining(entry -> {
                        taskMap.put(entry.getKey(), entry.getValue().asText());

                        try {
                            Class.forName(entry.getValue().asText());
                        } catch (ClassNotFoundException e) {
                            logger.error("Failed to load task class: {}", entry.getValue().asText(), e);
                        }
                    });
                    taskClzMap = taskMap;
                }
            }
        } catch (Exception e) {
            logger.error("Failed to load tasker_mapper.json", e);
            // 使用默认值作为fallback
            taskClzMap = Map.of();
        }
    }

    public void onMessage(SessionInfo session, JsonNode jsonNode) {
        // 处理 sessionId 的消息
        String sessionId = jsonNode.get(WebSocketConstant.SESSION_ID_FIELD_NAME).asText();
        try {
            handleAsSessionCallback(session, sessionId, jsonNode);
        } catch (Exception e) {
            sendError(session, sessionId, WebSocketConstant.ERROR_CODE_INTERNAL_SERVER_ERROR, e.getMessage());
            logger.warn("处理会话回调失败 (会话ID: {}): {}", sessionId, e.getMessage(), e);
        }
    }

    private void sendError(SessionInfo session, String sessionId, int errorCode, String message) {
        try {
            session.sendError(WebSocketConstant.SESSION_ID_FIELD_NAME, sessionId, errorCode, message);
        } catch (IOException e) {
            logger.warn("发送错误消息失败 (消息ID: {}): {}", sessionId, e.getMessage(), e);
        }
    }

    private void handleAsSessionCallback(SessionInfo session, String sessionId, JsonNode jsonNode) {
        if (!jsonNode.has("type")) {
            throw new IllegalArgumentException("缺失 type 参数");
        }
        String type = jsonNode.get("type").asText();
        if (type.equals("createTask")) {
            createTask(session, sessionId, jsonNode);
        }
    }

    private void createTask(SessionInfo session, String sessionId, JsonNode jsonNode) {
        if (!jsonNode.has(WebSocketConstant.ARGUMENTS_FIELD_NAME)) {
            throw new IllegalArgumentException("缺失 " + WebSocketConstant.ARGUMENTS_FIELD_NAME + " 参数");
        }
        JsonNode argsNode = jsonNode.get(WebSocketConstant.ARGUMENTS_FIELD_NAME);

        String taskName = argsNode.get(0).asText();
        String clzName = taskClzMap.get(taskName);
        if (clzName == null) {
            throw new IllegalArgumentException("未知的任务类型: " + taskName);
        }
        Object tasker = null;
        try {
            Class<?> clz = Class.forName(clzName);
            tasker = clz.getDeclaredConstructor().newInstance();
        } catch (ClassNotFoundException e) {
            throw new IllegalArgumentException("未知的任务类型: " + taskName + ", class: " + clzName);
        } catch (Exception e) {
            throw new IllegalArgumentException("任务类型: " + taskName + ", class: " + clzName + " 实例化失败");
        }

        if (tasker instanceof Tasker<?> t) {
            String locale = argsNode.get(1).asText();
            t.setLocale(Locale.forLanguageTag(locale));
        }

        if (tasker instanceof WebSocketServerTasker t) {
            t.setSession(session);
            t.setTitleHandler(title -> sendToSession(session, sessionId, "title", title));
            t.setMessageHandler(msg -> sendMessageToSession(session, sessionId, msg));
            t.setPropertyHandler((name, value) -> {
                if (value instanceof Voable<?> voable) {
                    value = voable.toVo();
                }
                sendToSession(session, sessionId, "property", name, value);
            });
            t.setProgressHandler((current, total) -> sendToSession(session, sessionId, "progress", current, total));
            t.init(argsNode.get(2));
        }

        if (tasker instanceof Callable<?> callable) {
            Thread.ofVirtual().start(() -> {
                try {
                    sendToSession(session, sessionId, "start");
                    callable.call();
                    sendToSession(session, sessionId, "done");
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
        }

    }

    private boolean sendMessageToSession(SessionInfo session, String sessionId, Message msg) {
        return sendToSession(session, sessionId, "message", msg.getLevel().getName(), msg.getMessage());
    }

    private boolean sendToSession(SessionInfo session, String sessionId, String type, Object... args) {
        try {
            session.send(Map.of(
                    WebSocketConstant.SESSION_ID_FIELD_NAME, sessionId,
                    "type", type,
                    WebSocketConstant.ARGUMENTS_FIELD_NAME, args));
            return true;
        } catch (IOException e) {
            logger.warn("发送消息失败 (消息ID: {}): {}", sessionId, e.getMessage(), e);
            return false;
        }
    }

    private void send(SessionInfo session, String sessionId, Object data) {
        Map<String, Object> map = new HashMap<>();
        if (data instanceof Voable<?>) {
            map.put("data", ((Voable<?>) data).toVo());
        } else {
            map.put("data", data);
        }
        map.put(WebSocketConstant.SESSION_ID_FIELD_NAME, sessionId);
        map.put(WebSocketConstant.SUCCESS_FIELD_NAME, true);
        try {
            session.send(map);
        } catch (IOException e) {
            logger.warn("发送消息失败 (消息ID: {}): {}", sessionId, e.getMessage(), e);
        }
    }
}
