package com.njzscloud.supervisory.order.controller;

import com.google.common.base.Strings;
import com.njzscloud.common.core.ex.ExceptionMsg;
import com.njzscloud.common.core.ex.Exceptions;
import com.njzscloud.common.core.utils.R;
import com.njzscloud.common.security.ex.UserLoginException;
import com.njzscloud.common.wechat.WechatUtil;
import com.njzscloud.common.wechat.param.Code2SessionParam;
import com.njzscloud.common.wechat.result.Code2SessionResult;
import com.njzscloud.supervisory.money.contant.MoneyChangeCategory;
import com.njzscloud.supervisory.money.pojo.entity.MoneyAccountEntity;
import com.njzscloud.supervisory.money.pojo.entity.MoneyChangeDetailEntity;
import com.njzscloud.supervisory.money.service.MoneyAccountService;
import com.njzscloud.supervisory.money.service.MoneyChangeDetailService;
import com.njzscloud.supervisory.order.contant.OrderStatus;
import com.njzscloud.supervisory.order.contant.PaymentStatus;
import com.njzscloud.supervisory.order.contant.PaymentWay;
import com.njzscloud.supervisory.order.contant.SettlementWay;
import com.njzscloud.supervisory.order.pojo.dto.*;
import com.njzscloud.supervisory.order.pojo.entity.OrderExpenseItemsEntity;
import com.njzscloud.supervisory.order.pojo.entity.OrderInfoEntity;
import com.njzscloud.supervisory.order.pojo.param.PaymentItemParam;
import com.njzscloud.supervisory.order.pojo.param.PaymentParam;
import com.njzscloud.supervisory.order.pojo.result.PaymentContextResult;
import com.njzscloud.supervisory.order.pojo.dto.RefundRequestDto;
import com.njzscloud.supervisory.order.service.OrderExpenseItemsService;
import com.njzscloud.supervisory.order.service.OrderInfoService;
import com.njzscloud.supervisory.order.service.WechatPayService;
import com.njzscloud.supervisory.sys.user.pojo.entity.UserAccountEntity;
import com.njzscloud.supervisory.sys.user.service.UserAccountService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.time.LocalDateTime;

/**
 * 支付相关接口
 */
@Slf4j
@RestController
@RequestMapping("/payment")
@RequiredArgsConstructor
public class PaymentController {

    private final OrderExpenseItemsService orderExpenseItemsService;
    private final OrderInfoService orderInfoService;
    private final MoneyAccountService moneyAccountService;
    private final MoneyChangeDetailService moneyChangeDetailService;
    private final WechatPayService wechatPayService;
    private final UserAccountService userAccountService;


    /**
     * 发起支付（占位接口，当前返回空支付内容）
     */
    @PostMapping("/pay")
    @Transactional(rollbackFor = Exception.class)
    public R<?> pay(@RequestBody PaymentParam paymentParam) {
        // 入参校验（占位）：支付方式、订单ID、支付清单不能为空
        if (paymentParam == null
                || paymentParam.getOrderId() == null
                || Strings.isNullOrEmpty(paymentParam.getPaymentCategory())
                || paymentParam.getSettleTotalMoney() == null
                || paymentParam.getSettleTotalMoney().signum() < 0
                || paymentParam.getItems() == null) {
            throw Exceptions.clierr("参数不完整或支付总金额小于0");
        }
        // 校验支付清单：id、名称、金额
        boolean invalidItem = paymentParam.getItems().stream().anyMatch(it ->
                it == null
                        || it.getId() == null
                        || it.getExpenseItemName() == null || it.getExpenseItemName().length() == 0
                        || it.getSettleMoney() == null || it.getSettleMoney().signum() < 0
        );
        if (invalidItem) {
            throw Exceptions.clierr("支付清单项不合法（id/名称/金额）");
        }

        // 校验支付方式
        if (paymentParam.getPaymentCategory() == null ||
                !(PaymentWay.WX.getVal().equals(paymentParam.getPaymentCategory()) ||
                        PaymentWay.COMPANY.getVal().equals(paymentParam.getPaymentCategory()))) {
            throw Exceptions.clierr("支付方式不合法");
        }

        // 校验数据库中结算金额是否与请求一致
        for (PaymentItemParam it : paymentParam.getItems()) {
            OrderExpenseItemsEntity entity = orderExpenseItemsService.getById(it.getId());
            if (entity == null) {
                throw Exceptions.clierr("支付清单项不存在，id=" + it.getId());
            }
            BigDecimal dbSettle = entity.getSettleMoney();
            BigDecimal reqSettle = it.getSettleMoney();
            if (dbSettle == null) {
                throw Exceptions.clierr("系统结算金额缺失，id=" + it.getId());
            }
            if (dbSettle.compareTo(reqSettle) != 0) {
                throw Exceptions.clierr("结算金额不一致【" + it.getExpenseItemName() + "】(id=" + it.getId()
                        + ")，系统:" + dbSettle + "，请求:" + reqSettle);
            }
        }

        // 查询订单及相关支付上下文（公司、司机账户）
        PaymentContextResult ctx = orderInfoService.paymentContext(paymentParam.getOrderId());
        if (ctx == null || ctx.getOrderId() == null) {
            throw Exceptions.clierr("订单不存在");
        }

        // 验证总金额是否与参数中的结算总金额一致
        if (paymentParam.getSettleTotalMoney() == null ||
                paymentParam.getSettleTotalMoney().compareTo(ctx.getSettleMoney()) != 0) {
            throw Exceptions.clierr("结算总金额与实际总金额不一致");
        }

        // 验证总金额是否与参数中的结算总金额一致（这里已经是第二层验证了）
        // 第一层验证在循环中已经完成：每个清单项的金额与数据库一致
        // 第二层验证：参数中的结算总金额与数据库统计总金额一致

        // 根据支付方式处理支付
        if (PaymentWay.COMPANY.getVal().equals(paymentParam.getPaymentCategory())) {
            // 公司支付：根据订单 trans_company_id -> biz_company.user_id -> money_account
            if (ctx.getTransCompanyId() == null || ctx.getCompanyUserId() == null) {
                throw Exceptions.clierr("订单未关联清运公司，无法公司支付");
            }
            
            // 根据结算方式判断是否需要检查余额
            if (SettlementWay.BALANCE.getVal().equals(ctx.getSettlementWay())) {
                // 余额结算：需要检查余额是否充足
                if (ctx.getCompanyBalance() == null || ctx.getCompanyBalance().compareTo(ctx.getSettleMoney()) < 0) {
                    throw Exceptions.clierr("公司账户余额不足");
                }
            }
            // 月结方式：不需要检查余额，允许余额为负数

            // 直接扣减公司账户余额
            deductCompanyBalance(ctx, ctx.getSettleMoney(), paymentParam.getOrderId());
        } else if (PaymentWay.WX.getVal().equals(paymentParam.getPaymentCategory())) {
            // 微信支付：创建微信支付订单
            WechatPayJsapiOrderDto orderDto = new WechatPayJsapiOrderDto();
            orderDto.setOutTradeNo("ORDER_" + ctx.getSn() + "_" + System.currentTimeMillis());
            orderDto.setDescription("订单支付-" + ctx.getSn());
            orderDto.setTotal(ctx.getSettleMoney().multiply(new BigDecimal("100")).longValue()); // 转换为分
            orderDto.setOpenid(ctx.getWechatOpenid());

            WechatPayJsapiOrderResponseDto response = wechatPayService.createMiniProgramOrder(orderDto);

            // 更新订单状态为待支付
            orderInfoService.lambdaUpdate()
                    .eq(OrderInfoEntity::getId, paymentParam.getOrderId())
                    .set(OrderInfoEntity::getPaymentStatus, PaymentStatus.WeiZhiFu)
                    .set(OrderInfoEntity::getPaymentCategory, paymentParam.getPaymentCategory())
                    .set(OrderInfoEntity::getOutTradeNo, orderDto.getOutTradeNo())
                    .update();

            log.info("微信支付订单创建成功，订单ID：{}，微信订单号：{}", paymentParam.getOrderId(), orderDto.getOutTradeNo());

            return R.success(response);
        } else {
            throw Exceptions.clierr("不支持的支付方式");
        }

        // 3. 更新订单支付状态为已支付（仅公司支付需要）
        if (PaymentWay.COMPANY.getVal().equals(paymentParam.getPaymentCategory())) {
            orderInfoService.lambdaUpdate()
                    .eq(OrderInfoEntity::getId, paymentParam.getOrderId())
                    .set(OrderInfoEntity::getPaymentStatus, PaymentStatus.YiZhiFu)
                    .set(OrderInfoEntity::getOrderStatus, OrderStatus.YiWanCheng.getVal())
                    .set(OrderInfoEntity::getPaymentCategory, paymentParam.getPaymentCategory())
                    .set(OrderInfoEntity::getPayTime, LocalDateTime.now())
                    .update();

            log.info("订单支付成功，订单ID：{}，支付方式：{}，支付金额：{}",
                    paymentParam.getOrderId(), paymentParam.getPaymentCategory(), ctx.getSettleMoney());
        }

        return R.success();
    }

    /**
     * 扣减公司账户余额
     */
    private void deductCompanyBalance(PaymentContextResult ctx, BigDecimal amount, Long orderId) {
        // 验证资金账户信息
        if (ctx.getCompanyAccountId() == null) {
            throw Exceptions.clierr("公司资金账户不存在");
        }

        BigDecimal oldBalance = ctx.getCompanyBalance();
        BigDecimal newBalance = oldBalance.subtract(amount);

        // 更新账户余额（支持负数余额）
        MoneyAccountEntity companyAccount = new MoneyAccountEntity()
                .setId(ctx.getCompanyAccountId())
                .setMoney(newBalance);
        moneyAccountService.updateById(companyAccount);

        // 记录资金变动明细
        MoneyChangeDetailEntity changeDetail = new MoneyChangeDetailEntity()
//                .setUserId(ctx.getCompanyUserId())
                .setCompanyId(ctx.getTransCompanyId())
                .setOrderId(orderId)
                .setMoneyAccountId(companyAccount.getId())
                .setOldMoney(oldBalance)
                .setDelta(amount.negate()) // 扣减为负数
                .setNewMoney(newBalance)
                .setMoneyChangeCategory(MoneyChangeCategory.DingDanKouKuan)
                .setMemo("订单支付扣款，订单ID：" + orderId + "，结算方式：" + ctx.getSettlementWay());

        moneyChangeDetailService.save(changeDetail);

        log.info("公司账户扣减成功，用户ID：{}，扣减金额：{}，余额：{} -> {}，结算方式：{}",
                ctx.getCompanyUserId(), amount, oldBalance, newBalance, ctx.getSettlementWay());
    }

    /**
     * 微信支付回调接口
     */
    @PostMapping("/wechat/callback")
    public ResponseEntity<String> wechatPayCallback(@RequestBody WechatPayCallbackDto callbackDto) {
        try {
            // 验证签名
            boolean isValid = wechatPayService.verifyCallback(
                    callbackDto.getId(),
                    callbackDto.getCreateTime(),
                    callbackDto.getEventType(),
                    callbackDto.getResource().getCiphertext()
            );
            if (!isValid) {
                log.error("微信支付回调签名验证失败");
                return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("FAIL");
            }

            // 处理支付结果
            if ("SUCCESS".equals(callbackDto.getResource().getOriginalType())) {
                // 支付成功，更新订单状态
                String outTradeNo = callbackDto.getResource().getCiphertext(); // 需要解密获取
                Long orderId = extractOrderIdFromOutTradeNo(outTradeNo);

                if (orderId != null) {
                    orderInfoService.lambdaUpdate()
                            .eq(OrderInfoEntity::getId, orderId)
                            .set(OrderInfoEntity::getPaymentStatus, PaymentStatus.YiZhiFu)
                            .set(OrderInfoEntity::getOrderStatus, OrderStatus.YiWanCheng.getVal())
                            .set(OrderInfoEntity::getSn, callbackDto.getResource().getCiphertext()) // 需要解密获取
                            .set(OrderInfoEntity::getPayTime, LocalDateTime.now())
                            .update();

                    log.info("微信支付成功，订单ID：{}，微信交易号：{}", orderId, callbackDto.getResource().getCiphertext());
                }
            }

            return ResponseEntity.ok("SUCCESS");
        } catch (Exception e) {
            log.error("处理微信支付回调异常", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("FAIL");
        }
    }

    /**
     * 查询微信支付订单状态
     */
    @GetMapping("/wechat/query/{outTradeNo}")
    public R<?> queryWechatPayOrder(@PathVariable String outTradeNo) {
        try {
            WechatPayOrderQueryResponseDto result = wechatPayService.queryOrder(outTradeNo);
            return R.success(result);
        } catch (Exception e) {
            log.error("查询微信支付订单异常，订单号：{}", outTradeNo, e);
            return R.failed();
        }
    }

    /**
     * 申请微信支付退款
     */
    @PostMapping("/wechat/refund")
    public R<?> wechatPayRefund(@RequestBody WechatPayRefundDto refundDto) {
        try {
            WechatPayRefundResponseDto result = wechatPayService.refund(refundDto);

            // 更新订单退款状态
            if ("SUCCESS".equals(result.getStatus())) {
                orderInfoService.lambdaUpdate()
                        .eq(OrderInfoEntity::getSn, refundDto.getOutTradeNo())
                        .set(OrderInfoEntity::getPaymentStatus, PaymentStatus.YiTuiKuan)
                        .set(OrderInfoEntity::getRefundTime, LocalDateTime.now())
                        .update();

                log.info("微信支付退款成功，订单号：{}，退款单号：{}", refundDto.getOutTradeNo(), result.getRefundId());
            }

            return R.success(result);
        } catch (Exception e) {
            log.error("微信支付退款异常，订单号：{}", refundDto.getOutTradeNo(), e);
            return R.failed();
        }
    }

    /**
     * 统一退款接口 - 支持微信退款和公司退款
     */
    @PostMapping("/refund")
    public R<?> refund(@RequestBody RefundRequestDto refundRequest) {
        try {
            // 验证订单存在性
            OrderInfoEntity orderInfo = orderInfoService.getById(refundRequest.getOrderId());
            if (orderInfo == null) {
                throw Exceptions.clierr("订单不存在");
            }

            // 验证订单状态
            if (!PaymentStatus.YiZhiFu.getVal().equals(orderInfo.getPaymentStatus().getVal())) {
                throw Exceptions.clierr("订单未支付，无法退款");
            }

            // 获取支付上下文
            PaymentContextResult ctx = orderInfoService.paymentContext(refundRequest.getOrderId());
            if (ctx == null) {
                throw Exceptions.clierr("获取支付上下文失败");
            }

            // 根据支付方式处理退款
            if (PaymentWay.WX.getVal().equals(ctx.getPaymentCategory())) {
                // 微信退款
//                return processWechatRefund(refundRequest, orderInfo, ctx);
                return R.success("退款成功");
            } else if (PaymentWay.COMPANY.getVal().equals(ctx.getPaymentCategory())) {
                // 公司退款
                return processCompanyRefund(refundRequest, ctx);
            } else {
                throw Exceptions.clierr("不支持的支付方式");
            }
        } catch (Exception e) {
            log.error("退款处理异常，订单ID：{}", refundRequest.getOrderId(), e);
            return R.failed(ExceptionMsg.CLI_ERR_MSG, "退款处理失败：" + e.getMessage());
        }
    }

    /**
     * 处理微信退款
     */
    private R<?> processWechatRefund(RefundRequestDto refundRequest, OrderInfoEntity orderInfo, PaymentContextResult ctx) {
        if (refundRequest.getWechatRefundParams() == null) {
            throw Exceptions.clierr("微信退款参数不能为空");
        }

        // 构建微信退款请求
        WechatPayRefundDto refundDto = new WechatPayRefundDto();
//        refundDto.setOutTradeNo(orderInfo.getOutTradeNo());
//        refundDto.setOutRefundNo(refundRequest.getWechatRefundParams().getOutRefundNo());
//        refundDto.setReason(refundRequest.getReason());
//        refundDto.setRefund(orderInfo.getSettleMoney().multiply(new BigDecimal("100")).longValue()); // 转换为分
//        refundDto.setTotal(orderInfo.getSettleMoney().multiply(new BigDecimal("100")).longValue()); // 转换为分
//        refundDto.setFundsAccount(refundRequest.getWechatRefundParams().getFundsAccount());
//        refundDto.setNotifyUrl(refundRequest.getWechatRefundParams().getNotifyUrl());

        // 调用微信退款接口
        WechatPayRefundResponseDto response = wechatPayService.refund(refundDto);

        // 更新订单状态为已退款
        orderInfoService.lambdaUpdate()
                .eq(OrderInfoEntity::getId, refundRequest.getOrderId())
                .set(OrderInfoEntity::getPaymentStatus, PaymentStatus.YiTuiKuan)
                .set(OrderInfoEntity::getRefundTime, LocalDateTime.now())
                .update();

        log.info("微信退款成功，订单ID：{}，退款单号：{}", refundRequest.getOrderId(), refundDto.getOutRefundNo());
        return R.success(response);
    }

    /**
     * 处理公司退款
     */
    private R<?> processCompanyRefund(RefundRequestDto refundRequest, PaymentContextResult ctx) {
        if (refundRequest.getRefundAmount() == null) {
            throw Exceptions.clierr("公司退款金额不能为空");
        }

        if (refundRequest.getRefundAmount().compareTo(BigDecimal.ZERO) <= 0) {
            throw Exceptions.clierr("退款金额必须大于0");
        }

        if (refundRequest.getRefundAmount().compareTo(ctx.getSettleMoney()) > 0) {
            throw Exceptions.clierr("退款金额不能超过订单已结算金额");
        }

        // 如果订单再次退款，本次退款金额+已退款金额不能大于结算金额
        if (refundRequest.getRefundAmount().add(ctx.getRefundMoney()).compareTo(ctx.getSettleMoney()) > 0) {
            throw Exceptions.clierr("退款金额总和不能超过订单已结算金额");
        }

        // 恢复公司账户余额
        restoreCompanyBalance(ctx, refundRequest.getRefundAmount(), refundRequest.getOrderId(), refundRequest.getReason());

        // 更新订单状态为已退款
        orderInfoService.lambdaUpdate()
                .eq(OrderInfoEntity::getId, refundRequest.getOrderId())
                .set(OrderInfoEntity::getPaymentStatus, PaymentStatus.YiTuiKuan)
                .set(OrderInfoEntity::getRefundTime, LocalDateTime.now())
                .update();

        log.info("公司退款成功，订单ID：{}，退款金额：{}", refundRequest.getOrderId(), refundRequest.getRefundAmount());
        return R.success("退款成功");
    }

    /**
     * 恢复公司账户余额
     */
    private void restoreCompanyBalance(PaymentContextResult ctx, BigDecimal refundAmount, Long orderId, String reason) {
        if (ctx.getCompanyUserId() == null || ctx.getCompanyAccountId() == null) {
            throw Exceptions.clierr("公司账户信息不完整，无法退款");
        }

        // 恢复公司账户余额
        BigDecimal oldBalance = ctx.getCompanyBalance();
        BigDecimal newBalance = oldBalance.add(refundAmount);
        MoneyAccountEntity companyAccount = new MoneyAccountEntity()
                .setId(ctx.getCompanyAccountId())
                .setMoney(newBalance);
        moneyAccountService.updateById(companyAccount);

        // 记录资金明细（这里需要实现资金明细记录功能）
        MoneyChangeDetailEntity changeDetail = new MoneyChangeDetailEntity()
                .setCompanyId(ctx.getTransCompanyId())
                .setOrderId(orderId)
                .setMoneyAccountId(companyAccount.getId())
                .setOldMoney(oldBalance)
                .setDelta(refundAmount) // 扣减为负数
                .setNewMoney(newBalance)
                .setMoneyChangeCategory(MoneyChangeCategory.DingDanTuiKuan)
                .setMemo(reason);

        moneyChangeDetailService.save(changeDetail);
        log.info("公司账户余额恢复成功，账户ID：{}，恢复金额：{}", ctx.getCompanyAccountId(), refundAmount);
    }

    /**
     * 从商户订单号中提取订单ID
     */
    private Long extractOrderIdFromOutTradeNo(String outTradeNo) {
        try {
            if (outTradeNo != null && outTradeNo.startsWith("ORDER_")) {
                String[] parts = outTradeNo.split("_");
                if (parts.length >= 2) {
                    return Long.parseLong(parts[1]);
                }
            }
        } catch (Exception e) {
            log.error("解析订单号失败：{}", outTradeNo, e);
        }
        return null;
    }

    /**
     * 绑定微信账号信息
     */
    @PostMapping("/wechat/bind")
    public R<?> bindWechatAccount(@RequestBody BindParam param) {
        // 通过userId查询用户账号信息
        UserAccountEntity userAccount = userAccountService.getOne(
            Wrappers.<UserAccountEntity>lambdaQuery()
                .eq(UserAccountEntity::getUserId, param.getUserId())
        );
        
        if (userAccount == null) {
            throw new UserLoginException(ExceptionMsg.CLI_ERR_MSG, "用户不存在");
        }
        
        // 调用微信API获取openId和unionId
        Code2SessionResult code2SessionResult = WechatUtil.code2Session(new Code2SessionParam().setJs_code(param.getWxCode()));
        Integer errcode = code2SessionResult.getErrcode();
        if (errcode != null && errcode != 0) {
            log.error("微信登录失败, errcode: {}, errmsg: {}", errcode, code2SessionResult.getErrmsg());
            throw new UserLoginException(ExceptionMsg.CLI_ERR_MSG, "微信登录失败");
        }
        
        String openid = code2SessionResult.getOpenid();
        String unionid = code2SessionResult.getUnionid();
        
        // 更新用户账号的微信信息
        userAccount.setWechatOpenid(openid);
        userAccount.setWechatUnionid(unionid);
        userAccountService.updateById(userAccount);
        
        return R.success("微信账号绑定成功");
    }

}


