package shop.alien.dining.config;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import shop.alien.dining.service.CartService;
import shop.alien.entity.store.dto.AddCartItemDTO;
import shop.alien.entity.store.dto.CartDTO;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 购物车WebSocket处理类
 * 支持双向通信：前端可以发送购物车变化，后端可以推送购物车更新
 *
 * @author system
 * @since 2025-01-XX
 */
@Slf4j
@Component
@ServerEndpoint(value = "/ws/cart/{tableId}", configurator = WebSocketConfig.WebSocketConfigurator.class)
public class CartWebSocketProcess implements ApplicationContextAware {

    private static ApplicationContext applicationContext;
    private static CartService cartService;

    // 存储每个桌号的WebSocket连接，一个桌号可以有多个连接(多个用户)
    private static final ConcurrentHashMap<Integer, ConcurrentHashMap<String, CartWebSocketProcess>> connections = new ConcurrentHashMap<>();

    /**
     * 会话对象
     */
    private Session session;

    /**
     * 桌号ID
     */
    private Integer tableId;

    /**
     * 连接ID
     */
    private String connectionId;

    @Override
    public void setApplicationContext(ApplicationContext context) {
        CartWebSocketProcess.applicationContext = context;
        CartWebSocketProcess.cartService = context.getBean(CartService.class);
    }

    /**
     * 客户端创建连接时触发
     */
    @OnOpen
    public void onOpen(@PathParam("tableId") Integer tableId, Session session) {
        try {
            this.session = session;
            this.tableId = tableId;
            // 设置30分钟超时
            this.session.setMaxIdleTimeout(30 * 60 * 1000);
            
            // 生成连接ID
            this.connectionId = "conn_" + System.currentTimeMillis() + "_" + Thread.currentThread().getId();

            // 存储连接
            connections.computeIfAbsent(tableId, k -> new ConcurrentHashMap<>()).put(connectionId, this);

            log.info("购物车WebSocket连接建立, tableId={}, connectionId={}", tableId, connectionId);

            // 发送连接成功消息
            sendMessage(createMessage("connected", "连接成功", null));

            // 发送当前购物车数据
            try {
                CartDTO cart = cartService.getCart(tableId);
                sendMessage(createMessage("cart_update", "购物车数据", cart));
            } catch (Exception e) {
                log.error("获取购物车数据失败, tableId={}", tableId, e);
            }

        } catch (Exception e) {
            log.error("WebSocket连接建立失败, tableId={}", tableId, e);
        }
    }

    /**
     * 接收到客户端消息时触发
     */
    @OnMessage
    public void onMessage(String message) {
        try {
            log.info("收到客户端消息, tableId={}, connectionId={}, message={}", tableId, connectionId, message);

            // 解析消息
            JSONObject jsonMessage = JSON.parseObject(message);
            String type = jsonMessage.getString("type");

            if (type == null) {
                sendError("消息类型不能为空");
                return;
            }

            // 处理不同类型的消息
            switch (type) {
                case "heartbeat":
                    // 心跳消息，直接回复
                    sendMessage(createMessage("heartbeat", "pong", null));
                    break;

                case "add_item":
                    // 添加商品到购物车
                    handleAddItem(jsonMessage);
                    break;

                case "update_quantity":
                    // 更新商品数量
                    handleUpdateQuantity(jsonMessage);
                    break;

                case "remove_item":
                    // 删除商品
                    handleRemoveItem(jsonMessage);
                    break;

                case "clear_cart":
                    // 清空购物车
                    handleClearCart();
                    break;

                default:
                    sendError("未知的消息类型: " + type);
                    break;
            }

        } catch (Exception e) {
            log.error("处理客户端消息失败, tableId={}, connectionId={}", tableId, connectionId, e);
            sendError("处理消息失败: " + e.getMessage());
        }
    }

    /**
     * 客户端连接关闭时触发
     */
    @OnClose
    public void onClose() {
        try {
            removeConnection();
            log.info("购物车WebSocket连接关闭, tableId={}, connectionId={}", tableId, connectionId);
        } catch (Exception e) {
            log.error("关闭WebSocket连接失败, tableId={}, connectionId={}", tableId, connectionId, e);
        }
    }

    /**
     * 连接发生异常时触发
     */
    @OnError
    public void onError(Throwable error) {
        log.error("WebSocket连接错误, tableId={}, connectionId={}", tableId, connectionId, error);
        removeConnection();
    }

    /**
     * 处理添加商品
     */
    private void handleAddItem(JSONObject jsonMessage) {
        try {
            JSONObject data = jsonMessage.getJSONObject("data");
            if (data == null) {
                sendError("添加商品数据不能为空");
                return;
            }

            AddCartItemDTO dto = new AddCartItemDTO();
            dto.setTableId(tableId);
            dto.setCuisineId(data.getInteger("cuisineId"));
            dto.setQuantity(data.getInteger("quantity"));
            dto.setRemark(data.getString("remark"));

            // 调用服务添加商品
            CartDTO cart = cartService.addItem(dto);

            // 推送更新给该桌号的所有连接
            pushCartUpdateToAll(tableId, cart);

            // 回复成功消息
            sendMessage(createMessage("add_item_success", "添加商品成功", cart));

        } catch (Exception e) {
            log.error("添加商品失败, tableId={}", tableId, e);
            sendError("添加商品失败: " + e.getMessage());
        }
    }

    /**
     * 处理更新商品数量
     */
    private void handleUpdateQuantity(JSONObject jsonMessage) {
        try {
            JSONObject data = jsonMessage.getJSONObject("data");
            if (data == null) {
                sendError("更新数量数据不能为空");
                return;
            }

            Integer cuisineId = data.getInteger("cuisineId");
            Integer quantity = data.getInteger("quantity");

            if (cuisineId == null || quantity == null) {
                sendError("菜品ID和数量不能为空");
                return;
            }

            // 调用服务更新数量
            CartDTO cart = cartService.updateItemQuantity(tableId, cuisineId, quantity);

            // 推送更新给该桌号的所有连接
            pushCartUpdateToAll(tableId, cart);

            // 回复成功消息
            sendMessage(createMessage("update_quantity_success", "更新数量成功", cart));

        } catch (Exception e) {
            log.error("更新商品数量失败, tableId={}", tableId, e);
            sendError("更新数量失败: " + e.getMessage());
        }
    }

    /**
     * 处理删除商品
     */
    private void handleRemoveItem(JSONObject jsonMessage) {
        try {
            JSONObject data = jsonMessage.getJSONObject("data");
            if (data == null) {
                sendError("删除商品数据不能为空");
                return;
            }

            Integer cuisineId = data.getInteger("cuisineId");
            if (cuisineId == null) {
                sendError("菜品ID不能为空");
                return;
            }

            // 调用服务删除商品
            CartDTO cart = cartService.removeItem(tableId, cuisineId);

            // 推送更新给该桌号的所有连接
            pushCartUpdateToAll(tableId, cart);

            // 回复成功消息
            sendMessage(createMessage("remove_item_success", "删除商品成功", cart));

        } catch (Exception e) {
            log.error("删除商品失败, tableId={}", tableId, e);
            sendError("删除商品失败: " + e.getMessage());
        }
    }

    /**
     * 处理清空购物车
     */
    private void handleClearCart() {
        try {
            // 调用服务清空购物车
            cartService.clearCart(tableId);

            // 创建空的购物车对象
            CartDTO cart = new CartDTO();
            cart.setTableId(tableId);
            cart.setItems(java.util.Collections.emptyList());
            cart.setTotalAmount(java.math.BigDecimal.ZERO);
            cart.setTotalQuantity(0);

            // 推送更新给该桌号的所有连接
            pushCartUpdateToAll(tableId, cart);

            // 回复成功消息
            sendMessage(createMessage("clear_cart_success", "清空购物车成功", cart));

        } catch (Exception e) {
            log.error("清空购物车失败, tableId={}", tableId, e);
            sendError("清空购物车失败: " + e.getMessage());
        }
    }

    /**
     * 推送购物车更新给该桌号的所有连接
     */
    private void pushCartUpdateToAll(Integer tableId, CartDTO cart) {
        ConcurrentHashMap<String, CartWebSocketProcess> tableConnections = connections.get(tableId);
        if (tableConnections != null && !tableConnections.isEmpty()) {
            tableConnections.forEach((connId, ws) -> {
                try {
                    ws.sendMessage(createMessage("cart_update", "购物车更新", cart));
                } catch (Exception e) {
                    log.error("推送购物车更新失败, tableId={}, connectionId={}", tableId, connId, e);
                }
            });
        }
    }

    /**
     * 发送消息
     */
    public void sendMessage(String message) {
        try {
            if (session != null && session.isOpen()) {
                session.getBasicRemote().sendText(message);
            }
        } catch (IOException e) {
            log.error("发送WebSocket消息失败, tableId={}, connectionId={}", tableId, connectionId, e);
            removeConnection();
        }
    }

    /**
     * 发送错误消息
     */
    private void sendError(String errorMessage) {
        sendMessage(createMessage("error", errorMessage, null));
    }

    /**
     * 创建消息JSON字符串
     */
    private String createMessage(String type, String message, Object data) {
        JSONObject json = new JSONObject();
        json.put("type", type);
        json.put("message", message);
        json.put("data", data);
        json.put("timestamp", System.currentTimeMillis());
        return json.toJSONString();
    }

    /**
     * 移除连接
     */
    private void removeConnection() {
        if (tableId != null && connectionId != null) {
            ConcurrentHashMap<String, CartWebSocketProcess> tableConnections = connections.get(tableId);
            if (tableConnections != null) {
                tableConnections.remove(connectionId);
                if (tableConnections.isEmpty()) {
                    connections.remove(tableId);
                }
            }
        }
    }

    /**
     * 静态方法：推送购物车更新（供外部调用，如HTTP接口）
     */
    public static void pushCartUpdate(Integer tableId, CartDTO cart) {
        ConcurrentHashMap<String, CartWebSocketProcess> tableConnections = connections.get(tableId);
        if (tableConnections != null && !tableConnections.isEmpty()) {
            String message = createStaticMessage("cart_update", "购物车更新", cart);
            tableConnections.forEach((connectionId, ws) -> {
                try {
                    ws.sendMessage(message);
                } catch (Exception e) {
                    log.error("推送购物车更新失败, tableId={}, connectionId={}", tableId, connectionId, e);
                }
            });
        }
    }

    /**
     * 静态方法：创建消息
     */
    private static String createStaticMessage(String type, String message, Object data) {
        JSONObject json = new JSONObject();
        json.put("type", type);
        json.put("message", message);
        json.put("data", data);
        json.put("timestamp", System.currentTimeMillis());
        return json.toJSONString();
    }
}
