package modules.user;

import com.alibaba.fastjson.JSONObject;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import common.jfinal.AppConfig;
import common.model.User;
import common.utils.bsn.BsnSDK;
import common.utils.http.MyRet;
import common.utils.hyg.HygSDK;

import java.util.*;
import java.util.stream.Collectors;

public class UserService {
    public String hello() {
        return "Hello User";
    }

    public MyRet saveUser(User user) {
        if (isUserExists(user.getStr("mobile_number"))) {
            return MyRet.fail("手机号已被注册。");
        }

        // 最终保存逻辑
        if (!user.save()) {
            return MyRet.fail("注册失败，请联系客服。");
        }

        // 生成Bsn地址
        try {
            JSONObject response = BsnSDK.createChainAccount("DLTBH_" + user.getId() + "_" + user.getCreateTime());
            
            if (response.getInteger("code") == -1) {
                throw new RuntimeException("地址创建失败：" + response);
            }
            
            JSONObject data = response.getJSONObject("data");
            String address = data.getString("opbChainClientAddress");
            
            if (StrKit.isBlank(address)) {
                throw new RuntimeException("地址创建成功，但获取失败：" + data);
            }
            
            user.setBsnAccountAddress(address);
            
            if (user.update()) {
                return MyRet.ok("注册成功。");
            } else {
                throw new RuntimeException("地址生成获取成功，但更新给用户失败");
            }
        } catch (Exception e) {
            String msg = "注册成功，但是BSN地址生成失败：" + e.getMessage() + ", 请联系客服处理。";
            return MyRet.fail(msg);
        }
    }
    
    public MyRet login(String mobileNumber, String pwdMd5Md5) {
        String findSQL = "select id, nickname, mobile_number, role, referrer_id, balance, create_time, update_time, is_deleted from t_user where "
                + "mobile_number = ? and pwd_md5_md5=?";
        User u = User.dao.findFirst(findSQL, mobileNumber, pwdMd5Md5);

        if (u == null) {
            return MyRet.fail("登录失败，密码错误。");
        } else {
            return MyRet.ok("登录成功。").setData(u);
        }
    }
    
    public MyRet verifyCodeLogin(String mobileNumber) {
        User u = findUserByMobileNumber(mobileNumber);

        if (u == null) {
            return MyRet.fail("验证码登录失败，违规操作将封禁ip。");
        } else {
            return MyRet.ok("登录成功。").setData(u);
        }
    }
    
    public void updateUserLoginTime(String mobileNumber) {
        String sql = "update t_user set login_time = ? where mobile_number = ?";

        Db.update(sql, System.currentTimeMillis(), mobileNumber);
    }

    public void updateToken(String mobileNumber, String token) {
        String sql = "update t_user set token = ? where mobile_number = ?";

        Db.update(sql, token, mobileNumber);
    }

    public String findMobileNumberByToken(String token) {
        String sql = "select mobile_number from t_user where token = ?";

        return Db.queryStr(sql, token);
    }

//    public String findWorkidByToken(String token) {
//        String sql = "select workid from t_user where token = ?";
//
//        return Db.queryStr(sql, token);
//    }

    public User findUserById(String id) {
        String sql = "select * from t_user where id = ?";

        return User.dao.findFirst(sql, id);
    }
    
    public MyRet team(long userId) {
        String sql = "select mobile_number, is_effective, create_time from t_user where referrer_id=?";
        List<User> teamUserList = User.dao.find(sql, userId);

        // 遍历 List<User>，对每个 User 的 mobile_number 进行脱敏处理
        for (User user : teamUserList) {
            String originalMobileNumber = user.getStr("mobile_number");
            String maskedMobileNumber;

            if (originalMobileNumber != null && originalMobileNumber.length() == 11) {
                // 假设手机号是标准的11位
                // 截取前3位：originalMobileNumber.substring(0, 3) 
                // 截取后4位：originalMobileNumber.substring(7) (从第7位开始到结束)
                maskedMobileNumber = originalMobileNumber.substring(0, 3) + "****" + originalMobileNumber.substring(7);
            } else if (originalMobileNumber != null && !originalMobileNumber.isEmpty()) {
                // 处理非11位手机号或短号的情况
                // 例如：如果长度小于7位，或者其他不规范的手机号
                // 这里可以根据实际需求进行更复杂的判断，例如：
                // 如果长度 >= 7，保留前3后4，中间替换
                // 如果长度 < 7，直接显示所有星号
                if (originalMobileNumber.length() >= 7) { // 至少能保留前3后4
                    maskedMobileNumber = originalMobileNumber.substring(0, 3) + "****" + originalMobileNumber.substring(originalMobileNumber.length() - 4);
                } else {
                    // 如果手机号过短，直接全部替换为星号
                    maskedMobileNumber = "********"; // 示例，也可以是固定长度的星号
                }
            } else {
                // originalMobileNumber == null 或者 originalMobileNumber.isEmpty()
                maskedMobileNumber = ""; // 或者设置为 null，或者你想表示为 "N/A"
            }

            user.set("mobile_number", maskedMobileNumber);
        }
        
        Map<String, Object> rst = new HashMap<>();
        rst.put("teamUserList", teamUserList);
        rst.put("count", teamUserList.size());
        
        return MyRet.ok("团队查询成功").setData(rst);
    }
    
    public User findUserByMobileNumber(String MobileNumber) {
        //, hyg_sign_rst
        String columns = "id, nickname, mobile_number, role, referrer_id, balance, login_time, hyg_worker_id, hyg_worker_details, hyg_bank_card, create_time, update_time, is_deleted";
        String sql = "select " + columns + " from t_user where mobile_number = ?";
        
        return User.dao.findFirst(sql, MobileNumber);
    }

    // public User findUserByBankCard(String bankCard) {
    //     //, hyg_sign_rst
    //     String columns = "id, balance";
    //     String sql = "select " + columns + " from t_user where hyg_bank_card = ?";
    //
    //     return User.dao.findFirst(sql, bankCard);
    // }
    
    public boolean isUserExists(String mobileNumber) {        
        return Db.queryLong("SELECT COUNT(1) FROM t_user WHERE mobile_number = ?", mobileNumber) > 0;
    }
    
    public void flushHygWorkerDetails(User user) {
        // 从慧用工处取得银行卡号，否则会导致充值信息无法匹配
        if (StrKit.notBlank(user.getHygWorkerId()) && StrKit.isBlank(user.getHygBankCard())) {
            try {
                JSONObject hygWorkerDetails = HygSDK.findWorkerDetails(user.getHygWorkerId());
                user.setHygWorkerDetails(hygWorkerDetails.toJSONString());
                user.update();
                
                // 首先保证接口调用成功
                if (hygWorkerDetails.getString("statusCode").equals("000000")) {
                    JSONObject data = hygWorkerDetails.getJSONObject("data");
                    
                    user.setHygBankCard(data.getString("bankCardNo"));
                    user.update();
                }
            } catch (Exception e) {
                AppConfig.LOGGER.error("慧用工接口调取错误：" + e.getMessage());
            }
        }
    }
    
    public Integer count(String keywords) {
        String searchKeyWord = "%" + keywords + "%";
        String sql = "SELECT COUNT(1) FROM t_user";
        String whereClause = " where id like ? or nickname like ? or mobile_number like ?";
        
        if (StrKit.isBlank(keywords)) {
            return Db.queryInt(sql);
        } else {
            return Db.queryInt(sql + whereClause, searchKeyWord, searchKeyWord, searchKeyWord);
        }
    }

    public List<User> users(int pageNumber, int pageSize, String keywords) {
        // limit 的第一个参数是偏移量，第二个参数是查询数量
        // 正确的 limit 是 LIMIT offset, count
        // offset = (pageNumber - 1) * pageSize
        // count = pageSize
        int offset = (pageNumber - 1) * pageSize;

        String searchKeyWord = "%" + keywords + "%";
        String columns = "id, nickname, mobile_number, role, referrer_id, balance, login_time, create_time, update_time, is_deleted";

        // SQL 语句构建修正
        // 基础 SQL 部分：SELECT ... FROM ... ORDER BY ... LIMIT
        String baseSql = "select " + columns + " from t_user order by login_time desc limit ?, ?";

        // 包含搜索条件的 WHERE 子句
        String whereClause = " where id like ? or nickname like ? or mobile_number like ?"; // 注意 id 的模糊查询

        // 如果没有关键词，只使用基础 SQL
        if (StrKit.isBlank(keywords)) {
            return User.dao.find(baseSql, offset, pageSize);
        } else {
            // 如果有关键词，将 WHERE 子句插入到 ORDER BY 前面
            // 完整的 SQL 结构应该是：SELECT ... FROM ... WHERE ... ORDER BY ... LIMIT
            String fullSql = "select " + columns + " from t_user " + whereClause + " order by login_time desc limit ?, ?";

            // 参数顺序：先是 WHERE 子句的参数，然后是 LIMIT 的参数
            return User.dao.find(fullSql, searchKeyWord, searchKeyWord, searchKeyWord, offset, pageSize);
        }
    }

    public MyRet teamInfoByAdmin() {
        // 1. 查询所有推荐人ID及其有效下级用户数量
        String queryReferrerStatsSql = "SELECT referrer_id, COUNT(id) AS valid_user_count " +
                "FROM t_user " +
                "WHERE is_effective = 1 AND referrer_id IS NOT NULL " +
                "GROUP BY referrer_id HAVING COUNT(id) > 0";
//        AppConfig.LOGGER.info("执行 SQL 查询推荐人统计: {}", queryReferrerStatsSql);
        List<Record> referrerStatsRecords = Db.find(queryReferrerStatsSql);

        if (referrerStatsRecords.isEmpty()) {
//            AppConfig.LOGGER.info("没有符合条件的推荐人。");
            return MyRet.fail("还没人推荐过任何人是有效用户。");
        }

        // 提取所有唯一的 referrer_id，并转换为 List 方便分批
        List<Long> eligibleReferrerIdsList = referrerStatsRecords.stream()
                .map(record -> record.getLong("referrer_id"))
                .distinct() // 确保唯一，虽然 Set 已经保证了
                .collect(Collectors.toList());
//        AppConfig.LOGGER.info("符合条件的推荐人ID数量: {}", eligibleReferrerIdsList.size());

        // 转换为 Map，方便通过 referrer_id 查找 valid_user_count (这个 Map 仍然需要)
        Map<Long, Integer> referrerValidUserCountMap = referrerStatsRecords.stream()
                .collect(Collectors.toMap(
                        record -> record.getLong("referrer_id"),
                        record -> record.getLong("valid_user_count").intValue()
                ));

        // ******** 2. 分批查询所有推荐人 User 对象，并直接整合 valid_user_count 到 User 对象中 ********
        final int BATCH_QUERY_SIZE = 1000;
        List<User> finalReferrerList = new ArrayList<>(eligibleReferrerIdsList.size()); // 最终的推荐人 User 对象列表

//        AppConfig.LOGGER.info("开始分批查询推荐人 User 对象并整合 valid_referred_count...");
        for (int i = 0; i < eligibleReferrerIdsList.size(); i += BATCH_QUERY_SIZE) {
            List<Long> subListReferrerIds = eligibleReferrerIdsList.subList(i, Math.min(i + BATCH_QUERY_SIZE, eligibleReferrerIdsList.size()));
            String subInSql = subListReferrerIds.stream().map(String::valueOf).collect(Collectors.joining(","));

            List<User> currentBatchUsers = User.dao.find("SELECT id, mobile_number, balance FROM t_user WHERE id IN (" + subInSql + ")");

            for (User referrer : currentBatchUsers) {
                // 直接在这里将 valid_user_count 整合进去
                Integer validUserCount = referrerValidUserCountMap.get(referrer.getId());
                if (validUserCount != null) {
                    referrer.put("valid_referred_count", validUserCount);
                }
            }
            finalReferrerList.addAll(currentBatchUsers);
//            AppConfig.LOGGER.debug("已查询推荐人批次 {} 总已查询用户数: {}", i, finalReferrerList.size());
        }
//        AppConfig.LOGGER.info("推荐人 User 对象查询并整合完毕，共查询到 {} 个推荐人。", finalReferrerList.size());

        // ******** 3. 分批查询所有被推荐用户（下级用户），并按推荐人 ID 分组 ********
//        AppConfig.LOGGER.info("开始分批查询所有被推荐用户（下级用户）并分组...");
        // 存储所有被推荐用户的数据，Key为referrer_id，Value为该referrer_id推荐的User的Map列表
        Map<Long, List<Map<String, Object>>> allReferredUsersByReferrerId = new HashMap<>();

        for (int i = 0; i < eligibleReferrerIdsList.size(); i += BATCH_QUERY_SIZE) {
            List<Long> subListReferrerIds = eligibleReferrerIdsList.subList(i, Math.min(i + BATCH_QUERY_SIZE, eligibleReferrerIdsList.size()));
            String subInReferrerSql = subListReferrerIds.stream().map(String::valueOf).collect(Collectors.joining(","));

            String queryReferredUsersSql = "SELECT id, mobile_number, effective_time, referrer_id " +
                    "FROM t_user " +
                    "WHERE is_effective = 1 " + // 确保是有效用户
                    "AND referrer_id IN (" + subInReferrerSql + ")" +
                    "ORDER BY effective_time ASC";

            List<Record> referredUserRecords = Db.find(queryReferredUsersSql);

            // 将 Record 转换为 Map<String, Object> 并按 referrer_id 分组
            for (Record record : referredUserRecords) {
                Long currentReferrerId = record.getLong("referrer_id");
                Map<String, Object> referredUser = new HashMap<>();
                referredUser.put("id", record.getLong("id"));
                referredUser.put("mobile_number", record.getStr("mobile_number"));
                referredUser.put("effective_time", record.getLong("effective_time"));

                allReferredUsersByReferrerId.computeIfAbsent(currentReferrerId, k -> new ArrayList<>()).add(referredUser);
            }
        }
//        AppConfig.LOGGER.info("所有被推荐用户查询并分组完毕。共找到被推荐用户 {} 条。",
//                allReferredUsersByReferrerId.values().stream().mapToInt(List::size).sum());

        // ******** 4. 将被推荐用户列表整合到推荐人 User 对象中 ********
//        AppConfig.LOGGER.info("开始将下级用户列表整合到推荐人 User 对象...");
        for (User referrer : finalReferrerList) { // 遍历已经整合了 valid_referred_count 的推荐人列表
            Long referrerId = referrer.getId();
            List<Map<String, Object>> referredUsers = allReferredUsersByReferrerId.getOrDefault(referrerId, Collections.emptyList()); // 使用 getOrDefault 避免 NPE

            referrer.put("referred_users", referredUsers); // put 进去一个 List<Map<String, Object>>
        }

//        AppConfig.LOGGER.info("直推网络查询与构建完成。");
        // ******** 分批查询 User 对象结束 ********
        
        // 筛选出直推人数大于等于10人的组，每个用户按第10位被推荐人（下级）的有效时间进行从小到大排序
        List<User> tenList = filterAndSortReferrersByNthReferralTime(finalReferrerList, 10);
        // 筛选出直推人数大于等于5人的组，每个用户按第5位被推荐人（下级）的有效时间进行从小到大排序
        List<User> fiveList = filterAndSortReferrersByNthReferralTime(finalReferrerList, 5);
        // 筛选出直推人数大于等于2人的组，每个用户按第2位被推荐人（下级）的有效时间进行从小到大排序
        List<User> twoList = filterAndSortReferrersByNthReferralTime(finalReferrerList, 2);
        
//        for (User referrer : tenList) {
//            Long referrerId = referrer.getId();
//            AppConfig.LOGGER.info("推荐人: {}", referrer.toJson());
//            List<Map<String, Object>> referredUsers = allReferredUsersByReferrerId.getOrDefault(referrerId, Collections.emptyList()); // 使用 getOrDefault 避免 NPE
//            AppConfig.LOGGER.debug("推荐人 {} 已关联 {} 个被推荐用户。", referrerId, referredUsers.size());
//
//            for (Map<String, Object> ru : referredUsers) {
//                AppConfig.LOGGER.info("     - ID:{}, 手机号:{}, 有效时间:{}", ru.get("id"), ru.get("mobile_number"), ru.get("effective_time"));
//            }
//        }
        
        Map<String, Object> rst = new HashMap<>();
        rst.put("referrer_list", finalReferrerList);
        rst.put("ten_list", tenList);
        rst.put("five_list", fiveList);
        rst.put("two_list", twoList);

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

    /**
     * 筛选出推荐人数大于等于指定阈值的推荐人，并按其第 N 位被推荐人的有效时间排序
     *
     * @param finalReferrerList 包含所有推荐人数据的 List<User>
     * @param threshold 筛选阈值，例如10，表示referred_users数量大于等于10的推荐人
     * @return 筛选并排序后的 List<User>
     */
    public List<User> filterAndSortReferrersByNthReferralTime(List<User> finalReferrerList, int threshold) {
        // @param nthIndex 排序依据的下级用户的索引（从0开始），例如9表示第10个被推荐人
        int nthIndex = threshold - 1;
//        AppConfig.LOGGER.info("开始筛选并排序推荐人列表，阈值: {}，排序依据的索引: {}", threshold, nthIndex);

        // 1. 筛选出 valid_referred_count 大于等于 threshold 的推荐人
        List<User> filteredList = finalReferrerList.stream()
                .filter(referrer -> {
                    Integer referredCount = referrer.get("valid_referred_count");
                    // 确保 referredCount 不为 null 且大于等于阈值
                    return referredCount != null && referredCount >= threshold;
                })
                .collect(Collectors.toList());

        AppConfig.LOGGER.info("筛选后，推荐人数大于等于 {} 的推荐人有 {} 位。", threshold, filteredList.size());

        if (filteredList.isEmpty()) {
            AppConfig.LOGGER.info("没有符合筛选条件的推荐人。");
            return filteredList;
        }

        // 2. 对筛选后的推荐人进行排序
        // 排序规则：按第 nthIndex 位被推荐人的 effective_time 升序
        try {
            filteredList.sort((referrer1, referrer2) -> {
                // 获取 referrer1 的第 nthIndex 位被推荐人的 effective_time
                List<Map<String, Object>> referredUsers1 = referrer1.get("referred_users");
                Long effectiveTime1 = null;
                if (referredUsers1 != null && referredUsers1.size() > nthIndex) {
                    Map<String, Object> nthUser1 = referredUsers1.get(nthIndex);
                    effectiveTime1 = (Long) nthUser1.get("effective_time");
                }

                // 获取 referrer2 的第 nthIndex 位被推荐人的 effective_time
                List<Map<String, Object>> referredUsers2 = referrer2.get("referred_users");
                Long effectiveTime2 = null;
                if (referredUsers2 != null && referredUsers2.size() > nthIndex) {
                    Map<String, Object> nthUser2 = referredUsers2.get(nthIndex);
                    effectiveTime2 = (Long) nthUser2.get("effective_time");
                }

                // 处理 null 值的情况：null 视为最大，排在最后
                if (effectiveTime1 == null && effectiveTime2 == null) {
                    return 0; // 都为null，视为相等
                } else if (effectiveTime1 == null) {
                    return 1; // referrer1 的时间为null，referrer2 不为null，referrer1 排在后面
                } else if (effectiveTime2 == null) {
                    return -1; // referrer2 的时间为null，referrer1 不为null，referrer2 排在后面
                } else {
                    return effectiveTime1.compareTo(effectiveTime2); // 升序排列
                }
            });
        } catch (ClassCastException e) {
            AppConfig.LOGGER.error("排序时发生类型转换错误，请检查 'effective_time' 字段的类型是否为 Long。", e);
            // 可以选择抛出异常或返回未排序的列表
        } catch (Exception e) {
            AppConfig.LOGGER.error("排序时发生未知错误。", e);
            // 可以选择抛出异常或返回未排序的列表
        }

//        AppConfig.LOGGER.info("筛选并排序完成，结果列表大小: {}", filteredList.size());
        return filteredList;
    }
}
