package com.ecep.contract;

import com.ecep.contract.constant.WebSocketConstant;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Getter;
import org.springframework.beans.BeanUtils;

import java.beans.PropertyDescriptor;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;

public class WebSocketClientSession {
    @Getter
    private String sessionId = UUID.randomUUID().toString();

    private WebSocketClientTasker tasker;

    private final WebSocketClientService webSocketService;

    public WebSocketClientSession(WebSocketClientService webSocketService) {
        this.webSocketService = webSocketService;
    }

    public void close() {
        webSocketService.closeSession(this);
    }

    public void submitTask(WebSocketClientTasker tasker, Locale locale, Object... args) throws JsonProcessingException {
        this.tasker = tasker;
        send("createTask", tasker.getTaskName(), locale.toLanguageTag(), args);
    }

    public void send(String type, Object... args) throws JsonProcessingException {
        Map<String, Object> arguments = Map.of(
                WebSocketConstant.SESSION_ID_FIELD_NAME, getSessionId(),
                "type", type,
                WebSocketConstant.ARGUMENTS_FIELD_NAME, args);
        webSocketService.send(arguments);
    }


    public void onMessage(JsonNode node) {
        if (node.has("type")) {
            String type = node.get("type").asText();
            JsonNode args = node.get(WebSocketConstant.ARGUMENTS_FIELD_NAME);
            if (type.equals("message")) {
                handleAsMessage(args);
            } else if (type.equals("title")) {
                handleAsTitle(args);
            } else if (type.equals("property")) {
                handleAsProperty(args);
            } else if (type.equals("progress")) {
                handleAsProgress(args);
            } else if (type.equals("start")) {
                handleAsStart(args);
            } else if (type.equals("done")) {
                handleAsDone(args);
            } else {
                tasker.updateMessage(java.util.logging.Level.INFO, "未知的消息类型: " + node.toString());
            }
        } else {
            tasker.updateMessage(java.util.logging.Level.INFO, "未知的消息: " + node.toString());
        }
    }

    private void handleAsDone(JsonNode args) {
        tasker.updateMessage(java.util.logging.Level.INFO, "任务完成");
        close();
    }

    private void handleAsStart(JsonNode args) {
        tasker.updateMessage(java.util.logging.Level.INFO, "任务开始");
    }

    private void handleAsProgress(JsonNode args) {
        long current = args.get(0).asLong();
        long total = args.get(1).asLong();
        tasker.updateProgress(current, total);
    }

    private void handleAsProperty(JsonNode args) {
        String name = args.get(0).asText();
        Object value = args.get(1);
        try {
            PropertyDescriptor descriptor = BeanUtils.getPropertyDescriptor(tasker.getClass(), name);
            System.out.println("descriptor = " + descriptor);
            System.out.println("descriptor.getPropertyType() = " + descriptor.getPropertyType());
            Object object = webSocketService.getObjectMapper().convertValue(value, descriptor.getPropertyType());
            System.out.println("object = " + object);
            System.out.println("descriptor.getWriteMethod() = " + descriptor.getWriteMethod());
            System.out.println("descriptor.getWriteMethod().getParameterTypes() = " + descriptor.getWriteMethod().getParameterTypes());
            descriptor.getWriteMethod().invoke(tasker, object);
        } catch (Exception e) {
            tasker.updateMessage(java.util.logging.Level.SEVERE, "属性设置失败: " + name + " = " + value);
        }
    }

    private void handleAsTitle(JsonNode args) {
        String message = args.get(0).asText();
        tasker.updateTitle(message);
    }

    private void handleAsMessage(JsonNode args) {
        String level = args.get(0).asText();
        String message = args.get(1).asText();
        updateMessage(java.util.logging.Level.parse(level), message);
    }

    public void updateMessage(Level level, String message) {
        tasker.updateMessage(level, message);
    }

}
