package com.ecep.contract.service;

import com.ecep.contract.PageArgument;
import com.ecep.contract.PageContent;
import com.ecep.contract.WebSocketClientService;
import com.ecep.contract.model.IdentityEntity;
import com.ecep.contract.model.NamedEntity;
import com.ecep.contract.util.ParamUtils;
import com.ecep.contract.vm.IdentityViewModel;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import javafx.util.StringConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;

public class QueryService<T extends IdentityEntity, TV extends IdentityViewModel<T>>
        implements ViewModelService<T, TV> {
    // 添加日志记录器
    private static final Logger logger = LoggerFactory.getLogger(QueryService.class);
    @Autowired
    protected WebSocketClientService webSocketService;
    @Autowired
    protected ObjectMapper objectMapper;

    @SuppressWarnings("unchecked")
    public TV createNewViewModel() {
        try {
            Type genericSuperclass = getClass().getGenericSuperclass();
            String typeName = genericSuperclass.getTypeName();
            // System.out.println("typeName = " + typeName);
            String clz = typeName.split("<")[1].split(">")[0].split(",")[1].trim();
            // System.out.println("clz = " + clz);
            Class<?> clazz = Class.forName(clz);
            return (TV) clazz.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException("无法创建ViewModel实例", e);
        }
    }

    @SuppressWarnings("unchecked")
    public T createNewEntity() {
        try {
            Type genericSuperclass = getClass().getGenericSuperclass();
            String typeName = genericSuperclass.getTypeName();
            // System.out.println("typeName = " + typeName);
            String clz = typeName.split("<")[1].split(">")[0].split(",")[0].trim();
            // System.out.println("clz = " + clz);
            Class<?> clazz = Class.forName(clz);
            return (T) clazz.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException("无法创建Entity实例", e);
        }
    }

    @Override
    public T save(T entity) {
        try {
            return async("save", entity, entity.getClass().getName()).handle((response, ex) -> {
                if (ex != null) {
                    throw new RuntimeException("保存实体失败", ex);
                }
                if (response != null) {
                    try {
                        objectMapper.updateValue(entity, response);
                    } catch (JsonMappingException e) {
                        throw new RuntimeException(e);
                    }
                }
                return entity;
            }).get();
        } catch (Exception e) {
            throw new RuntimeException("保存实体失败", e);
        }
    }

    @Override
    public void delete(T entity) {
        try {
            async("delete", entity, entity.getClass().getName()).handle((response, ex) -> {
                if (ex != null) {
                    throw new RuntimeException("删除实体失败", ex);
                }
                if (response != null) {
                    return updateValue(entity, response);
                }
                return null;
            }).get();
        } catch (Exception e) {
            logger.error("删除实体失败 #{}", entity.getId(), e);
            throw new RuntimeException("删除实体失败", e);
        }
    }

    public T updateValue(T entity, JsonNode node) {
        try {
            objectMapper.updateValue(entity, node);
        } catch (JsonMappingException e) {
            throw new RuntimeException(e);
        }
        return entity;
    }

    public CompletableFuture<JsonNode> async(String method, Object... params) {
        return webSocketService.invoke(getBeanName(), method, params).handle((response, ex) -> {
            if (ex != null) {
                throw new RuntimeException("远程方法+" + method + "+调用失败", ex);
            }
            return response;
        });
    }

    public CompletableFuture<T> asyncFindById(Integer id) {
        return async("findById", id, Integer.class).handle((response, ex) -> {
            if (ex != null) {
                throw new RuntimeException("查询实体失败", ex);
            }
            T newEntity = createNewEntity();
            return updateValue(newEntity, response);
        });
    }

    @Override
    public T findById(Integer id) {
        try {
            return asyncFindById(id).get();
        } catch (Exception e) {
            logger.error("查询实体失败 #{}", id, e);
            throw new RuntimeException("查询实体失败", e);
        }
    }

    public List<T> findAll() {
        return findAll(null, Pageable.unpaged()).getContent();
    }

    /**
     * 异步查询所有实体数据，返回CompletableFuture对象
     *
     * @param params   查询参数映射表，可以包含过滤条件等信息
     * @param pageable 分页参数，包含页码、每页条数、排序规则等
     * @return 包含分页结果的CompletableFuture对象
     */
    public CompletableFuture<Page<T>> asyncFindAll(Map<String, Object> params, Pageable pageable) {
        // 调用async方法发送WebSocket请求，获取异步响应结果
        return async("findAll", params, PageArgument.of(pageable)).handle((response, ex) -> {
            if (ex != null) {
                throw new RuntimeException("远程方法+findAll+调用失败", ex);
            }
            try {
                // 将响应结果转换为PageContent对象，使用当前类的createNewEntity方法创建实体实例
                PageContent<T> pageContent = of(response, objectMapper, this::createNewEntity);
                // 将PageContent转换为Spring Data的Page对象并返回
                return pageContent.toPage();
            } catch (Exception e) {
                // 处理转换过程中的异常，包装为RuntimeException并附带响应内容
                throw new RuntimeException("响应结果转换失败, JSON = " + response.toString(), e);
            }
        });
    }

    /**
     * 同步查询所有实体数据，实现了ViewModelService接口的findAll方法
     *
     * @param params   查询参数映射表，可以包含过滤条件等信息
     * @param pageable 分页参数，包含页码、每页条数、排序规则等
     * @return 包含查询结果的Page对象
     * @throws RuntimeException 当查询失败时抛出异常
     */
    @Override
    public Page<T> findAll(Map<String, Object> params, Pageable pageable) {
        try {
            if (pageable == null) {
                pageable = Pageable.unpaged();
            }
            // 调用异步方法并阻塞等待结果返回
            return asyncFindAll(params, pageable).get();
        } catch (Exception e) {
            // 处理异步查询过程中的任何异常，转换为运行时异常抛出
            throw new RuntimeException("查询失败, 参数：" + params, e);
        }
    }

    /**
     * 异步执行计数操作，返回CompletableFuture<Long>类型结果
     *
     * @param params 包含计数所需参数的Map集合
     * @return 返回一个CompletableFuture<Long>对象，用于获取异步操作的结果
     */
    public CompletableFuture<Long> asyncCount(Map<String, Object> params) {
        // 调用async方法执行名为"count"的异步操作，传入参数params
        // 使用handle方法处理异步操作的结果或异常
        return async("count", params).handle((response, ex) -> {
            if (ex != null) {
                throw new RuntimeException("远程方法+count+调用失败", ex);
            }
            // 将响应结果转换为Long类型并返回
            return response.asLong();
        });
    }

    public long count(Map<String, Object> params) {
        try {
            return asyncCount(params).get();
        } catch (Exception e) {
            throw new RuntimeException("计数失败", e);
        }
    }

    public List<T> search(String searchText) {
        ParamUtils.Builder params = getSpecification(searchText);
        List<T> list = findAll(params.build(), Pageable.ofSize(10)).getContent();
        return list;
    }

    public static <T> PageContent<T> of(JsonNode response, ObjectMapper objectMapper, Supplier<T> createNewEntity)
            throws JsonProcessingException {

        PageContent<T> pageContent = new PageContent<>();
        List<T> content = new ArrayList<>();
        if (response.has("content")) {
            JsonNode contentNode = response.get("content");
            if (contentNode != null && contentNode.isArray()) {
                for (JsonNode node : contentNode) {
                    T newEntity = createNewEntity.get();
                    objectMapper.updateValue(newEntity, node);
                    content.add(newEntity);
                }
            }
        }
        pageContent.setContent(content);
        if (response.has("page")) {
            JsonNode pageNode = response.get("page");
            PageArgument pageArgument = objectMapper.treeToValue(pageNode, PageArgument.class);
            pageContent.setPage(pageArgument);
        }
        if (response.has("totalElements")) {
            int totalElements = response.get("totalElements").asInt();
            pageContent.setTotalElements(totalElements);
        }
        if (response.has("totalPages")) {
            int totalPages = response.get("totalPages").asInt();
            pageContent.setTotalPages(totalPages);
        }
        return pageContent;
    }

    public StringConverter<T> getStringConverter() {
        return new StringConverter<>() {
            @Override
            public String toString(T object) {
                if (object instanceof NamedEntity named) {
                    return named.getName();
                }
                return object.toString();
            }

            @Override
            public T fromString(String string) {
                return null;
            }
        };
    }
}