package modules.order;

import com.alibaba.fastjson.JSONObject;
import com.jfinal.aop.Inject;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import common.model.BalanceLog;
import common.model.Order;
import common.model.OrderLog;
import common.model.User;
import common.utils.http.MyRet;
import modules.nftt.NfttService;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class OrderService {
    @Inject
    NfttService nfttService;
    
    public String hello() {
        return "Hello order";
    }
    
    public MyRet create(long nfttId, long userId, int orderType) {
        float quantity = 1;
        
        try {
            Db.tx(() -> {
                // 1. SELECT ... FOR UPDATE: 查询商品库存，并对该商品行加排他锁
                Record item = Db.findFirst("SELECT purchased_quantity, max_quantity, price FROM t_nftt WHERE id = ? FOR UPDATE", nfttId);
                
                if (item == null) {
                    throw new RuntimeException("商品不存在: " + nfttId);
                }

                int stock = item.getInt("max_quantity") - item.getInt("purchased_quantity");
                if (stock <= 0) {
                    throw new RuntimeException("库存不足");
                }
                float unitPrice = item.getFloat("price");
                float totalPrice = unitPrice * quantity;

                // 判断用户余额并预扣
                User user = User.dao.findById(userId);
                if (user.getBalance() < totalPrice) {
                    throw new RuntimeException("余额不足，请充值。需要: " + totalPrice + "，你有：" + user.getBalance());
                }
                user.setBalance(user.getBalance() - totalPrice);
                if (!user.update()) {
                    throw new RuntimeException("创建信息时，用户信息更新失败 user id: " + user.getId());
                }
                BalanceLog l = new BalanceLog();
                l.set("create_time", System.currentTimeMillis());
                l.set("is_deleted", 0);
                l.set("description", "用户购买NFT：" + nfttId + "，消费"); // 描述中带上百分比
                l.set("amount", -totalPrice);
                l.set("user_id", user.getLong("id"));
                if (!l.save()) {
                    throw new RuntimeException("消费记录创建失败: " + user.getId());
                }

                // 2. 更新库存（在锁定的行上进行）
                Db.update("UPDATE t_nftt SET purchased_quantity = purchased_quantity + 1 WHERE id = ?", nfttId);
                
                // 3. 创建订单
                Order order = new Order();
                String orderSn = generateOrderSn();                                         // 生成唯一订单号

                order.set("order_sn", orderSn);
                order.set("user_id", userId);
                order.set("nftt_id", nfttId);
                order.set("order_status", OrderController.OrderStatus.PAID.code);    // 初始状态：待支付
                order.set("order_type", orderType);                                         // 订单类型：1=正式购买, 2=预购
                order.set("quantity", quantity);
                // ... 获取单价、计算总价 ...
                order.set("unit_price", unitPrice);
                order.set("total_price", totalPrice);
                // ... 支付方式 ...
                order.set("payment_method", 1);
                // ... 交付状态 ...
                order.set("delivery_status", 0);
                // ... nft铸造状态 ...
                order.set("nft_mint_status", 0);
                // 退款状态
                order.set("refund_status", 0);
                // 相关时间戳
                order.set("create_time", System.currentTimeMillis());
                order.set("update_time", System.currentTimeMillis());
                order.set("is_deleted", 0);
                
                if (!order.save()) {
                    throw new RuntimeException("创建订单失败, nftt id=" + nfttId + ", user id=" + userId + ", order type=" + orderType);
                }

                // 3. 记录订单创建日志
                OrderLog log = new OrderLog();
                log.set("order_id", order.getId());
                log.set("from_status", OrderController.OrderStatus.INIT.code);
                log.set("to_status", OrderController.OrderStatus.PAID.code);
                log.set("operator_id", userId); // 由用户创建
                log.set("operator_type", 1);
                log.set("change_reason", "订单创建");
                log.set("create_time", System.currentTimeMillis());
                if (!log.save()) {
                    throw new RuntimeException("订单日志创建失败"); // 抛出异常触发回滚
                }

                return true;
            });

            return MyRet.ok(orderType == 1 ? "抢购成功" : "预购成功");
        } catch (Exception e) {
            return MyRet.fail(e.getMessage());
        }
    }
    
    public MyRet cancelByUser(long userId, long orderId) {
        try {
            Db.tx(() -> {
                // 1. 获取order和nfttId
                String sql = "SELECT * FROM t_order WHERE id=? FOR UPDATE";
                Order order = Order.dao.findFirst(sql, orderId);

                // 订单状态判断
                if (order.getOrderStatus() == OrderController.OrderStatus.COMPLETED.code
                        || order.getOrderStatus() == OrderController.OrderStatus.CANCELED.code
                        || order.getOrderStatus() == OrderController.OrderStatus.REFUNDED.code) {
                    throw new RuntimeException("无法取消已完成的订单，请刷新后尝试");
                }
                
                // 已转账订单判断
                if (StrKit.notBlank(order.getBsnTransferCode())) {
                    throw new RuntimeException("该订单的NFT已转出，无法取消");
                }
                
                long nfttId = order.getNfttId();
                
                // 2. 更新库存（在锁定的行上进行）
                if (Db.update("UPDATE t_nftt SET purchased_quantity = purchased_quantity - 1 WHERE id = ?", nfttId) != 1) {
                    throw new RuntimeException("更新库存失败导致的取消失败");
                }

                // 3. 取消订单
                order.set("order_status", OrderController.OrderStatus.CANCELED.code);
                order.set("update_time", System.currentTimeMillis());
                
                if (!order.update()) {
                    throw new RuntimeException("订单更新失败导致的取消失败");
                }

                // 4. 记录订单创建日志
                OrderLog log = new OrderLog();
                log.set("order_id", order.getId());
                log.set("from_status", order.getOrderStatus());
                log.set("to_status", OrderController.OrderStatus.CANCELED.code);
                log.set("operator_id", userId); // 由用户取消
                log.set("operator_type", 1);
                log.set("change_reason", "用户手动取消");
                log.set("create_time", System.currentTimeMillis());
                if (!log.save()) {
                    throw new RuntimeException("订单日志创建失败"); // 抛出异常触发回滚
                }
                
                // 5. 还给人家
                User user = User.dao.findById(userId);
                user.setBalance(user.getBalance() + order.getTotalPrice());
                if (!user.update()) {
                    throw new RuntimeException("归还失败"); // 抛出异常触发回滚
                }
                // 6. 归还记录
                BalanceLog l = new BalanceLog();
                l.set("create_time", System.currentTimeMillis());
                l.set("is_deleted", 0);
                l.set("description", "用户取消订单：" + orderId + "，退还"); // 描述中带上百分比
                l.set("amount", order.getTotalPrice());
                l.set("user_id", user.getLong("id"));
                if (!l.save()) {
                    throw new RuntimeException("取消订单归还记录创建失败: " + user.getId());
                }
                
                return true;
            });

            return MyRet.ok("取消成功");
        } catch (Exception e) {
            return MyRet.fail(e.getMessage());
        }
    }

    public MyRet findOrderById(long orderId, long userId) {
        List<Order> orderList = Order.dao.find("SELECT * FROM t_order WHERE id=? and user_id=?", orderId, userId);

//        // 给用户转账NFT
//        doNftTransfer(userId, orderList);
        
        // 给用户订单封装商品信息
        for (Order order : orderList) {
            order.put("nftt", nfttService.findNfttById(order.getNfttId() + ""));
        }
        
        List<Map<String, Object>> resultList = encapsulateOrdersWithLogs(orderList);

        if (!resultList.isEmpty()) {
            return MyRet.ok("查询成功").setData(resultList.get(0));
        } else {
            return MyRet.fail("未找到订单号对应的订单");
        }
    }
    
    public MyRet findNftListByUser(long userId) {
        String columns = "id, nftt_id, order_status, order_type, delivery_status, delivery_time, nft_mint_status, bsn_transfer_code, bsn_transfer_status";
        String sql = "SELECT " + columns + " FROM t_order WHERE user_id = ? ORDER BY create_time DESC";
        List<Order> allOrderList = Order.dao.find(sql, userId);
//        
//        // 给用户转账NFT
//        doNftTransfer(userId, allOrderList);

        // 创建一个新的列表来存储过滤后的订单
        List<Order> filteredOrders = new ArrayList<>();

        // 控制给用户的返回值
        for (Order order : allOrderList) {
            if (order.getDeliveryStatus() == 1 
                    && order.getOrderStatus() == OrderController.OrderStatus.COMPLETED.code 
                    && order.getNftMintStatus() == 4) {
                filteredOrders.add(order);
            }
        }
        
        // 给放入txHash，移除bsh_transfer_status
        for (Order order : filteredOrders) {
            JSONObject bsn = JSONObject.parseObject(order.getBsnTransferStatus());
            
            String hash = bsn.getJSONObject("data").getString("txHash");
            order.remove("bsn_transfer_status");
            order.put("tx_hash", hash);
            order.put("tx_query_url", String.format("https://taianexplorer.bsnbase.com/transaction-detail?data=%s&type=some", hash));
        }

        // 给用户订单封装商品信息
        for (Order order : filteredOrders) {
            order.put("nftt", nfttService.findNfttById(order.getNfttId() + ""));
        }

        return MyRet.ok("查询成功").setData(filteredOrders);
    }

    /**
     * 根据用户ID查询订单列表，并封装订单流转状态
     * @param userId 用户ID
     * @param status 需要的状态
     * @return 包含订单列表及状态流转信息的 MyRet 对象
     */
    public MyRet findOrderByUser(long userId, int status) {
        List<Order> allOrderList = Order.dao.find("SELECT * FROM t_order WHERE user_id = ? ORDER BY create_time DESC", userId);

        if (allOrderList.isEmpty()) {
            return MyRet.ok("查询成功").setData(new ArrayList<Map<String, Object>>());
        }

//        // 给用户转账NFT
//        doNftTransfer(userId, allOrderList);
        
        // 只需要指定状态的status
        List<Order> filteredOrderList = new ArrayList<>();
        
        // 状态过滤
        for (Order order : allOrderList) {
            // -1就不用过滤了
            if (status == -1) {
                filteredOrderList.add(order);
                continue;
            }
            
            // 否则就按指定状态来
            if (order.getOrderStatus() == status) {
                filteredOrderList.add(order);
            }
        }
        
        // 给用户订单封装商品信息
        for (Order order : filteredOrderList) {
            order.put("nftt", nfttService.findNfttById(order.getNfttId() + ""));
        }

        // 调用重用方法封装日志
        List<Map<String, Object>> resultList = encapsulateOrdersWithLogs(filteredOrderList);

        return MyRet.ok("查询成功").setData(resultList);
    }

    /**
     * 管理员查询订单列表（分页，按更新时间倒序，根据订单状态筛选）
     * 按照用户提供的分页逻辑计算 total_row 和 total_page
     * @param pageNumber 页码
     * @param pageSize 页面大小
     * @param orderStatus 订单状态码 (用于筛选，可选，如果为null或小于0则不筛选)
     * @return 包含分页订单列表及状态流转信息的 MyRet 对象
     */
    public MyRet findForAdmin(int pageNumber, int pageSize, Integer orderStatus) { 
        // 接收 Integer 类型的 orderStatus
        // 构建用于查询当前页订单列表的 SQL
        String columns = "id, order_sn, user_id, nftt_id, order_status, order_type, quantity, unit_price, total_price, payment_method, payment_sn, pay_time, delivery_status, delivery_time, cancel_time, closed_time, refund_status, refund_amount, refund_reason, create_time, update_time, is_deleted, memo";
        String select = "SELECT " + columns;
        String fromWhere = "FROM t_order"; // 基础 from 子句
        String orderBy = "ORDER BY update_time DESC";

        List<Object> paramsForList = new ArrayList<>(); // 用于 SELECT 列表查询的参数

        // ✅ 根据 orderStatus 筛选
        if (orderStatus != null && orderStatus >= 0) { // 确保 orderStatus 有效，0 通常表示“已取消”，也作为有效状态
            fromWhere += " WHERE order_status = ?";
            paramsForList.add(orderStatus);
        }

        // 计算 LIMIT 的 offset (偏移量)
        int offset = (pageNumber - 1) * pageSize;

        // 构建查询当前页订单列表的最终 SQL (手动添加 LIMIT)
        String listSql = select + " " + fromWhere + " " + orderBy + " LIMIT ?, ?";
        paramsForList.add(offset);
        paramsForList.add(pageSize);

        // 获取当前页的订单列表
        List<Order> orderList = Order.dao.find(listSql, paramsForList.toArray());

        // 如果列表为空，直接返回
        if (orderList.isEmpty()) {
            Map<String, Object> response = new HashMap<>(); // 准备返回结构
            response.put("list", new ArrayList<>());
            response.put("total_row", 0);
            response.put("total_page", 0);
            response.put("page_size", pageSize);
            response.put("page_number", pageNumber);
            response.put("total_order_count", 0); // 与你的 total_user_count 对应
            return MyRet.ok("查询成功").setData(response);
        }

        // 重用封装日志的逻辑
        List<Map<String, Object>> encapsulatedOrderList = encapsulateOrdersWithLogs(orderList);

        // 获取符合搜索条件的总行数 (total_row)
        // 调用新的 countOrders 方法，传入 orderStatus 进行筛选计数
        long totalRowLong = countOrders(orderStatus);

        // 手动计算 total_page
        int totalPage = (int) Math.ceil((double) totalRowLong / pageSize);
        if (totalPage == 0 && totalRowLong > 0) { // 解决总行数大于0但总页数为0（pageSize大于totalRow）的问题
            totalPage = 1;
        }

        // 封装最终响应
        Map<String, Object> response = new HashMap<>();
        response.put("list", encapsulatedOrderList);
        response.put("total_row", totalRowLong); // 符合条件的订单总数
        response.put("total_page", totalPage); // 手动计算的总页数
        response.put("page_size", pageSize);
        response.put("page_number", pageNumber);
        response.put("total_order_count", totalRowLong); // 对应 total_user_count，这里是符合订单状态筛选的总数

        return MyRet.ok("查询成功").setData(response);
    }
    
    /**
     * 【重用方法】封装订单列表及其状态流转日志
     * @param orderList 原始订单列表
     * @return 封装了日志和描述信息的订单列表
     */
    private List<Map<String, Object>> encapsulateOrdersWithLogs(List<Order> orderList) {
        if (orderList.isEmpty()) {
            return new ArrayList<>();
        }

        // 2. 获取所有订单的ID，用于批量查询订单日志
        List<Long> orderIds = orderList.stream()
                .map(order -> order.getLong("id"))
                .collect(Collectors.toList());

        // 确保 orderIds 不为空，避免 SQL 错误
        if (orderIds.isEmpty()) {
            return new ArrayList<>();
        }

        // 3. 一次性查询所有订单相关的状态日志
        StringBuilder inClause = new StringBuilder();
        for (int i = 0; i < orderIds.size(); i++) {
            inClause.append("?");
            if (i < orderIds.size() - 1) {
                inClause.append(",");
            }
        }
        String sql = "SELECT * FROM t_order_log WHERE order_id IN (" + inClause + ") ORDER BY order_id, create_time ASC";
        List<OrderLog> orderLogs = OrderLog.dao.find(sql, orderIds.toArray());

        // 4. 将日志按 order_id 分组
        Map<Long, List<Map<String, Object>>> orderLogsMap = new HashMap<>();
        for (OrderLog log : orderLogs) {
            long orderId = log.getLong("order_id");
            orderLogsMap.computeIfAbsent(orderId, k -> new ArrayList<>())
                    .add(convertOrderLogToMap(log));
        }

        // 5. 遍历订单列表，封装日志和状态描述
        List<Map<String, Object>> resultList = new ArrayList<>();
        for (Order order : orderList) {
            Map<String, Object> orderData = order.toMap();

            orderData.put("order_status_desc", getStatusDescByCode(order.getInt("order_status")));

            List<Map<String, Object>> currentOrderLogs = orderLogsMap.getOrDefault(order.getLong("id"), new ArrayList<>());
            orderData.put("status_history", currentOrderLogs);

            resultList.add(orderData);
        }
        return resultList;
    }

    public long countOrders(Integer orderStatus) { // 接收 Integer 类型的 orderStatus
        String sql = "SELECT COUNT(id) FROM t_order"; // COUNT(id) 更清晰
        List<Object> params = new ArrayList<>();

        // ✅ 根据 orderStatus 筛选
        if (orderStatus != null && orderStatus >= 0) {
            sql += " WHERE order_status = ?";
            params.add(orderStatus);
        }
        return Db.queryLong(sql, params.toArray());
    }
    
    public boolean isOrderBelongToUser(long userId, long orderId) {
        String sql = "SELECT COUNT(1) FROM t_order" +
                " WHERE id=? and user_id=?"; 
        
        return Db.queryInt(sql, orderId, userId) != 1;
    }

    /**
     * 辅助方法：将 OrderLog Model 转换为 Map，并添加状态描述
     * @param log OrderLog 对象
     * @return 包含描述信息的 Map
     */
    private Map<String, Object> convertOrderLogToMap(OrderLog log) {
        Map<String, Object> logMap = log.toMap(); // 获取原始日志属性

        // 添加状态描述
        logMap.put("from_status_desc", getStatusDescByCode(log.getInt("from_status")));
        logMap.put("to_status_desc", getStatusDescByCode(log.getInt("to_status")));

        return logMap;
    }

    /**
     * 根据状态码获取状态描述
     * 假设你已经定义了 OrderStatus 枚举
     *
     * @param statusCode 状态码
     * @return 状态描述字符串
     */
    private String getStatusDescByCode(int statusCode) {
        for (OrderController.OrderStatus status : OrderController.OrderStatus.values()) {
            if (status.code == statusCode) {
                return status.desc;
            }
        }
        return "未知状态"; // 如果找不到对应的状态码
    }
    
    public static String generateOrderSn() {
        return System.currentTimeMillis() + "" + (int)(Math.random() * 10000);
    }
}
