package modules.withdraw;

import com.alibaba.fastjson.JSONObject;
import com.jfinal.plugin.activerecord.Db;
import common.jfinal.AppConfig;
import common.model.BalanceLog;
import common.model.User;
import common.model.Withdraw;
import common.utils.http.MyRet;
import common.utils.hyg.HygSDK;
import modules.order.OrderService;

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

public class WithdrawService {
    // 提现手续费，750代表万分之750(7.5%)
    public static final long WITHDRAW_FEE = 750;
    
    public String hello() {
        return "Hello Withdraw";
    }
    
    public MyRet create(long amount, User user) {
        long amountWithoutFee = amount * (10000 - WITHDRAW_FEE) / 10000;
        
        // 用户余额判断
        if (user.getBalance() < (float)amount) {
            return MyRet.fail(String.format("提现失败，余额不足，你仅有%s而提现%s", user.getBalance(), amount));
        }
        
        try {
            String orderSn = "DLTBH_WD_" + OrderService.generateOrderSn();

            Db.tx(() -> {
                user.setBalance(user.getBalance() - (float)amount);
                
                if (!user.update()) {
                    throw new RuntimeException("用户余额扣减失败");
                }

                // 保存提现单据
                Withdraw withdraw = new Withdraw();
                withdraw.setWithdrawSn(orderSn);
                withdraw.setAmount((float)amount);
                withdraw.setStatus(10);
                withdraw.setUserId(user.getId());
                withdraw.setCreateTime(System.currentTimeMillis());
                withdraw.setUpdateTime(System.currentTimeMillis());
                withdraw.setIsDeleted(0);

                // 保存资金流水
                BalanceLog l = new BalanceLog();
                l.set("create_time", System.currentTimeMillis());
                l.set("is_deleted", 0);
                l.set("description", "用户提现：" + amount); // 描述中带上百分比
                l.set("amount", -amount);
                l.set("user_id", user.getLong("id"));
                if (!l.save()) {
                    throw new RuntimeException("资金流水记录创建失败: " + user.getId());
                }
                
                if (!withdraw.save()) {
                    throw new RuntimeException("提现单据保存失败");
                }
                
                return true;
            });

            float amountCNY = (float)amountWithoutFee / (float)100;
            float feePercent = (float)WITHDRAW_FEE / (float)100;
            return MyRet.ok(String.format("提现%s，实际到账%.2f(元)，手续费%s%%，申请已提交", amount, amountCNY, feePercent)).setData(findByWithdrawSn(orderSn));
        } catch (Exception e) {
            return MyRet.fail("提现申请失败: " + e.getMessage());
        }
    }
    
    public MyRet pass(Withdraw withdraw, long approverId) {
        // 记录操作人
        withdraw.setApproverId(approverId);
        
        try {
            User user = User.dao.findById(withdraw.getUserId());
            long amountWithoutFee = (long) (withdraw.getAmount() * (10000 - WITHDRAW_FEE) / 10000);

            String workerId = user.getHygWorkerId();
            String amountWithoutFeeStr = amountWithoutFee + "";
            String hygPositionId = System.getenv("HYG_POSITION_ID");

            AppConfig.LOGGER.info("{}, {}, {}, {}", workerId, amountWithoutFeeStr, withdraw.getWithdrawSn(), hygPositionId);
            JSONObject withdrawRst = HygSDK.singleDistribute(workerId, amountWithoutFeeStr, withdraw.getWithdrawSn(), hygPositionId);
            
            // 首先保证提现是成功的
            if (!withdrawRst.getString("statusCode").equals("000000")) {
                withdraw.setHygOrigin(withdrawRst.toString());
                withdraw.setReason("慧用工提现失败");
                withdraw.setStatus(40);
                
                // 原子化操作user和withdraw的状态
                Db.tx(() -> {
                    // 把款项退给用户
                    user.setBalance(user.getBalance() + withdraw.getAmount());
                    if (!user.update()) {
                        throw new RuntimeException("用户余额归还失败");
                    }

                    if (!withdraw.update()) {
                        throw new RuntimeException("单据状态更新失败");
                    }

                    // 保存资金流水
                    BalanceLog l = new BalanceLog();
                    l.set("create_time", System.currentTimeMillis());
                    l.set("is_deleted", 0);
                    l.set("description", "慧用工转款失败退还"); // 描述中带上百分比
                    l.set("amount", withdraw.getAmount());
                    l.set("user_id", user.getLong("id"));
                    if (!l.save()) {
                        throw new RuntimeException("资金流水记录创建失败: " + user.getId());
                    }
                    
                    return true;
                });
                
                return MyRet.fail("慧用工提现失败：" + withdrawRst.getString("statusText"));
            }
            
            // 如果是成功提现
            withdraw.setHygOrigin(withdrawRst.toString());
            withdraw.setStatus(20);
            if (withdraw.update()) {
                return MyRet.ok("打款请求已发起").setData(withdraw);
            } else {
                return MyRet.fail("单据状态更新失败");
            }
        } catch (Exception e) {
            return MyRet.fail("打款请求已发起失败: " + e.getMessage());
        }
    }
    
    public MyRet refuse(Withdraw withdraw, String reason, long approverId) {
        User user = User.dao.findById(withdraw.getUserId());

        try {
            Db.tx(() -> {
                user.setBalance(user.getBalance() + withdraw.getAmount());
                
                if (!user.update()) {
                    throw new RuntimeException("用户余额扣减失败");
                }
                
                // 记录操作人
                withdraw.setApproverId(approverId);
                withdraw.setReason(reason);
                withdraw.setStatus(40);

                if (!withdraw.update()) {
                    throw new RuntimeException("提现单据保存失败");
                }

                // 管理员拒绝
                BalanceLog l = new BalanceLog();
                l.set("create_time", System.currentTimeMillis());
                l.set("is_deleted", 0);
                l.set("description", "管理员拒绝提现，请查看原因"); // 描述中带上百分比
                l.set("amount", withdraw.getAmount());
                l.set("user_id", user.getLong("id"));
                if (!l.save()) {
                    throw new RuntimeException("资金流水记录创建失败: " + user.getId());
                }
                
                return true;
            });
            
            return MyRet.ok("该单据已拒绝").setData(withdraw);
        } catch (Exception e) {
            return MyRet.fail("拒绝失败：" + e.getMessage());
        }
    }
    
    public MyRet list(int pageNumber, int pageSize, Integer status, Long userId) {
        // 接收 Integer 类型的 orderStatus
        // 构建用于查询当前页订单列表的 SQL
        String columns = " * ";
        String select = "SELECT " + columns;
        StringBuilder fromWhere = new StringBuilder("FROM t_withdraw"); // 基础 from 子句
        String orderBy = "ORDER BY update_time DESC";
        boolean hasWhereClause = false; // 标志位，用于判断是否已经添加了 WHERE 关键字

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

        // ✅ 根据 status 筛选
        if (status != null && status >= 0) { // status 通常是枚举，>=0 可能是有效的判断
            fromWhere.append(hasWhereClause ? " AND" : " WHERE").append(" status = ?");
            params.add(status);
            hasWhereClause = true;
        }

        // ✅ 根据 userId 筛选
        // 通常 userId 是正整数，如果 userId 可能为 0 需要特别对待
        if (userId != null && userId > 0) { // 通常 userId 从 1 开始，或者根据你的业务逻辑设定
            fromWhere.append(hasWhereClause ? " AND" : " WHERE").append(" user_id = ?");
            params.add(userId);
            hasWhereClause = true;
        }
        
        // 计算 LIMIT 的 offset (偏移量)
        int offset = (pageNumber - 1) * pageSize;

        // 构建查询当前页订单列表的最终 SQL (手动添加 LIMIT)
        String listSql = select + " " + fromWhere + " " + orderBy + " LIMIT ?, ?";
        params.add(offset);
        params.add(pageSize);
        
        List<Withdraw> withdrawList = Withdraw.dao.find(listSql, params.toArray());

        // 如果列表为空，直接返回
        if (withdrawList.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);
        }

        // 获取符合条件的条目数量
        long totalRowLong = countWithdraws(status, userId);

        // 手动计算 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", withdrawList);
        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);
    }

    public long countWithdraws(Integer status, Long userId) { // 接收 Integer 类型的 status
        StringBuilder sql = new StringBuilder("SELECT COUNT(*) FROM t_withdraw"); // 使用 COUNT(*)，更通用
        List<Object> params = new ArrayList<>();
        boolean hasWhereClause = false; // 标志位，用于判断是否已经添加了 WHERE 关键字

        // ✅ 根据 status 筛选
        if (status != null && status >= 0) { // status 通常是枚举，>=0 可能是有效的判断
            sql.append(hasWhereClause ? " AND" : " WHERE").append(" status = ?");
            params.add(status);
            hasWhereClause = true;
        }

        // ✅ 根据 userId 筛选
        // 通常 userId 是正整数，如果 userId 可能为 0 需要特别对待
        if (userId != null && userId > 0) { // 通常 userId 从 1 开始，或者根据你的业务逻辑设定
            sql.append(hasWhereClause ? " AND" : " WHERE").append(" user_id = ?");
            params.add(userId);
            hasWhereClause = true;
        }

        // 执行查询并返回结果
        // Db.queryLong() 如果没有结果会返回 null，如果查询结果行数为 0，则返回 Long 0
        // 这符合 COUNT() 函数的预期
        return Db.queryLong(sql.toString(), params.toArray());
    }
    
    public Withdraw findByWithdrawSn(String sn) {
        return Withdraw.dao.findFirst("SELECT * FROM t_withdraw WHERE withdraw_sn=?", sn);
    }
}
