package com.repair.controller;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.repair.api.RepairPayRecordControllerAPI;
import com.repair.common.utils.*;
import com.repair.model.enumModel.eIsSuccess;
import com.repair.model.enumModel.eIsSuper;
import com.repair.model.enumModel.ePayPageStatu;
import com.repair.model.enumModel.eRecordStatu;
import com.repair.model.pojo.*;
import com.repair.model.request.RefundableAmountRequest;
import com.repair.model.request.repairPayRequest;
import com.repair.model.result.CommonResult;
import com.repair.model.result.PageUtils;
import com.repair.model.vo.ProsperityRepairPayRecordsVo;
import com.repair.model.vo.QueryExportVo;
import com.repair.model.vo.StatisticsVo;
import com.repair.services.*;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static com.repair.common.utils.StrUtils.getUUIDBits;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author ceshi
 * @since 2023-07-20
 */
@RestController
public class RepairPayRecordController implements RepairPayRecordControllerAPI {

    @Autowired
    private RepairRecordService repairRecordService;
    @Autowired
    private RepairPayRecordService repairPayRecordService;
    @Autowired
    private RepairSystemMessagesService repairSystemMessagesService;
    @Autowired
    private RepairUserService repairUserService;

    @Autowired
    private RepairRefundRecordService repairRefundRecordService;

    @Autowired
    private RepairAdminService repairAdminService;

    @Override
    public CommonResult InsertrepairPayRecord(RepairPayRecord rc, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            String st = paramUtils.getParamError(bindingResult);
            return CommonResult.fail(st);
        }

        int result = repairPayRecordService.insertRepairPayRecord(rc);

        return result > 0 ? CommonResult.ok("添加成功") : CommonResult.fail("添加失败");
    }

    @Override
    public CommonResult updaterepairPayRecordById(RepairPayRecord rc, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            String st = paramUtils.getParamError(bindingResult);
            return CommonResult.fail(st);
        }

        int result = repairPayRecordService.updateRepairPayRecord(rc);

        return result > 0 ? CommonResult.ok("修改成功") : CommonResult.fail("修改失败");
    }

    @Override
    public CommonResult queryPagerepairPayRecords(int currentPage, int pageCount, String name) {
        PageUtils<RepairPayRecord> result = repairPayRecordService.queryPageRepairPayRecords(currentPage, pageCount, name);

        return CommonResult.ok(result);
    }

    @Override
    public CommonResult deleterepairPayRecordById(int id) {
        RepairPayRecord data = repairPayRecordService.getRepairById(id);
        if (data == null) {
            return CommonResult.fail("当前数据不存在，删除失败！");
        }

        int result = repairPayRecordService.deleteRepairPayRecordById(id);

        return result > 0 ? CommonResult.ok("删除成功") : CommonResult.fail("删除失败");
    }

    @Override
    public CommonResult repairPayment(repairPayRequest rpr, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            String st = paramUtils.getParamError(bindingResult);
            return CommonResult.fail(st);
        }

        RepairRecord data = repairRecordService.getRepairById(rpr.getRecordId());
        if (data == null) {
            return CommonResult.fail("维修单数据异常,支付失败");
        }

        if (data.getMaintenanceState() != eRecordStatu.ToConfirmed.getValue()) {
            return CommonResult.fail("订单状态异常，支付失败");
        }

        if (data.getPrice().compareTo(rpr.getPrice()) != 0) {
            return CommonResult.fail("支付金额与订单金额不一致");
        }

        //查找是否存在支付成功的数据，有的话提示已经支付过了
        RepairPayRecord payData = repairPayRecordService.getRepairPaySuccessByRecordId(rpr.getRecordId());
        if (payData != null) {
            return CommonResult.fail("该订单已支付，请勿重复操作");
        }
        String payResult = null;
        try {
            //支付金额和订单都为0元的时候不唤起支付模块
            payResult = notifyPay(TimeExchange.DateToString(new Date(), "yyyyMMddHHmmss"), data.getRecordNo(), rpr.getPrice().toString(), getUUIDBits(15), "02", "2", "1234567891");
            if (!payResult.equals("success")) {
                return CommonResult.fail("支付失败");
            }
        } catch (Exception e) {
            return CommonResult.fail("支付失败");
        }

        return CommonResult.ok("支付成功");
    }

    /**
     * 支付回调接口
     *
     * @param orderDate   交易日期时间 格式为：yyyyMMddHHmmss 24小时制
     * @param orderNo     订单号
     * @param amount      订单金额
     * @param jylsh       支付平台交易流水号
     * @param tranStat    订单支付状态
     * @param return_type 通知类型
     * @param sign        订单签名数据
     * @return
     */
    @Transactional(rollbackFor = {Exception.class})
    public String notifyPay(String orderDate, String orderNo, String amount, String jylsh, String tranStat, String return_type, String sign) throws Exception {

        try {
            // 除去sign参数外，通知接口各参数皆是待签名参数。按照参数列表顺序，以“key=value&key1=value1”方式生成待签名字符串，再拼接密钥。进行MD5运算生成签名。
            // 示例：
            // 密钥：key=umz4aea6g97skeect0jtxigvjkrimd0o
            // 待签名字符串：
            // orderDate=20140319163131&orderNo=1403190004&amount=10.00&jylsh=1303190000001&tranStat=1&return_type=1
            // 报文：
            // orderDate=20140319163131&orderNo=1403190004&amount=10.00&jylsh=1303190000001&tranStat=1&return_type=1umz4aea6g97skeect0jtxigvjkrimd0o
            // 签名：3c797055ef08c16f296d1c28b696f301

            RepairPayRecord data = repairPayRecordService.queryPaymentData(orderNo);

            RepairRecord rr = repairRecordService.queryRepairByRecordno(orderNo);
            if (rr == null) {
                throw new Exception("支付回调失败！");
            }

            if (rr.getPrice().compareTo(new BigDecimal(amount)) != 0) {
                throw new Exception("支付回调失败！");
            }
            //是否支付成功 未支付/等待支付：1；支付成功：2；支付失败：3
            //可能支付平台会重复回调 所以原来支付成功的订单就不用处理了
            if (data != null) {
                if (data.getIsSuccess().equals(2)) {
                    return "success";
                }
                data.setIsSuccess(Integer.valueOf(tranStat));
                data.setRemark(data.getRemark() + "/n" + tranStat);

                int updateData = repairPayRecordService.updateRepairPayRecord(data);
                if (updateData <= 0) {
                    throw new Exception("支付回调失败！");
                }

            } else {
                data = new RepairPayRecord();
                data.setRecordId(rr.getId());
                data.setUserId(rr.getUserId());
                data.setPayNo(jylsh);
                data.setPayPrice(new BigDecimal(amount));
                data.setIsSuccess(Integer.valueOf(tranStat));
                data.setRemark(return_type);
                int insertData = repairPayRecordService.insertRepairPayRecord(data);

                if (insertData <= 0) {
                    throw new Exception("支付回调失败！");
                }
            }

            if (tranStat.equals("02")) {
                //用户成功支付完成后将维修单状态由待确认改为维修中
                rr.setMaintenanceState(eRecordStatu.Maintenance.getValue());
                int rrData = repairRecordService.updateRepairRecord(rr);
                if (rrData <= 0) {
                    throw new Exception("支付回调失败！");
                }
                //将支付成功消息发送给师傅
                String[] userIds = rr.getMaintenancerId().split(",");
                if(userIds.length > 0){
                    List<RepairSystemMessages> rsms = new ArrayList<>();
                    for (int i = 0;i<userIds.length;i++){
                        RepairSystemMessages rsm = new RepairSystemMessages();
                        rsm.setIsRead(0);
                        rsm.setRecordId(data.getId());
                        rsm.setRecipientId(Integer.valueOf(userIds[i]));
                        rsm.setContent("用户已支付，请尽快处理！");
                        rsms.add(rsm);
                    }
                    boolean insertRsm =repairSystemMessagesService.inserBatchSystemMessage(rsms);
                    if(!insertRsm){
                        throw new Exception("支付回调失败！");
                    }
                }
            }

        } catch (Exception e) {
            throw new Exception("支付回调失败！");
        }

        return "success";
    }

    /**
     * 支付成功分页
     *
     * @param currentPage
     * @param pageCount
     * @param keyWord
     * @param startTime
     * @param endTime
     * @return
     */
    @Override
    public CommonResult queryProsperityRepairPayRecords(int currentPage, int pageCount, String keyWord, String startTime, String endTime) {

        if (startTime != null && endTime != null) {
            try {
                startTime = TimeExchange.getStartOfDayStr(TimeExchange.StringToDate(startTime, "yyyy-MM-dd"));
                endTime = TimeExchange.getEndOfDayStr(TimeExchange.StringToDate(endTime, "yyyy-MM-dd"));
            } catch (Exception e) {
            }
        }


        if (currentPage <= 0 && pageCount <= 0) {
            currentPage = 1;
            pageCount = 10;
        }

//      判断是否为名字
        LambdaQueryWrapper<RepairUser> userWrapper = new LambdaQueryWrapper<>();
        userWrapper.like(ObjectUtils.isNotEmpty(keyWord), RepairUser::getUserName, keyWord);

        ArrayList<Integer> userIdList = new ArrayList<>();

        List<RepairUser> list = repairUserService.list(userWrapper);
        if (ObjectUtils.isNotEmpty(list) && list.size() >= 0) {
            list.forEach(repairUser -> {
                userIdList.add(repairUser.getId());
            });
        } else {
            userIdList.add(0);
        }

        ArrayList<Integer> recordList = new ArrayList<>();
        LambdaQueryWrapper<RepairRecord> recordWrapper = new LambdaQueryWrapper<>();
        recordWrapper.like(ObjectUtils.isNotEmpty(keyWord),RepairRecord::getRecordNo,keyWord);
        List<RepairRecord> list2 = repairRecordService.list(recordWrapper);
        if (ObjectUtils.isNotEmpty(list2) && list2.size() >= 0) {
            list2.forEach(repairRecord -> {
                recordList.add(repairRecord.getId());
            });
        } else {
            recordList.add(0);
        }


        LambdaQueryWrapper<RepairPayRecord> wrapper = new LambdaQueryWrapper<>();


        wrapper.in(ObjectUtils.isNotEmpty(keyWord), RepairPayRecord::getUserId, userIdList)
                .between(ObjectUtils.isNotEmpty(startTime) && ObjectUtils.isNotEmpty(endTime), RepairPayRecord::getCreateTime, startTime, endTime)
                .eq(RepairPayRecord::getIsSuccess, eIsSuccess.Succeed.getValue())
                .or()
                .in(ObjectUtils.isNotEmpty(keyWord), RepairPayRecord::getRecordId, recordList)
                .between(ObjectUtils.isNotEmpty(startTime) && ObjectUtils.isNotEmpty(endTime), RepairPayRecord::getCreateTime, startTime, endTime)
                .eq(RepairPayRecord::getIsSuccess, eIsSuccess.Succeed.getValue());

        IPage<RepairPayRecord> page = repairPayRecordService.page(new Page<>(currentPage, pageCount), wrapper);

        IPage<ProsperityRepairPayRecordsVo> prpr = new Page<>();
        BeanUtils.copyProperties(page, prpr);


        ArrayList<ProsperityRepairPayRecordsVo> vos = new ArrayList<>();

//    订单号
        ArrayList<Integer> recordIdList = new ArrayList<>();

//        报修人id
        List<Integer> userIds = new ArrayList<>();

        List<RepairPayRecord> records = page.getRecords();
//        获取所有订单号
        if (ObjectUtils.isEmpty(records)) {
            records.forEach(repairPayRecord -> {
                recordIdList.add(repairPayRecord.getRecordId());
                userIds.add(repairPayRecord.getUserId());
            });
        }

//        通过订单号查询退款记录
        LambdaQueryWrapper<RepairRefundRecord> rrrsWrapepr = new LambdaQueryWrapper<>();
        rrrsWrapepr.in(RepairRefundRecord::getRecordId, recordIdList)
                .eq(RepairRefundRecord::getIsSuccess, eIsSuccess.Succeed.getValue());

        List<RepairRefundRecord> refundRecords = repairRefundRecordService.list(rrrsWrapepr);

//        通过人员id查询用户
        LambdaQueryWrapper<RepairUser> userListWrapper = new LambdaQueryWrapper<>();
        userListWrapper.in(RepairUser::getId, userIds)
                .select(RepairUser::getId, RepairUser::getUserName);

        List<RepairUser> users = repairUserService.list(userListWrapper);


        LambdaQueryWrapper<RepairRecord> rrWrapper = new LambdaQueryWrapper<>();
        rrWrapper.in(RepairRecord::getId, recordIdList);
        List<RepairRecord> list1 = repairRecordService.list(rrWrapper);

        records.forEach(rpr -> {
            ProsperityRepairPayRecordsVo prrpv = new ProsperityRepairPayRecordsVo();
            BeanUtils.copyProperties(rpr, prrpv);
//            交易时间
            prrpv.setPayTime(rpr.getCreateTime());

            Integer recordId = rpr.getRecordId();

//            工单号
            for (RepairRecord repairRecord : list1) {
                Integer id = repairRecord.getId();
                if (id.equals(recordId)) {
                    prrpv.setRecordNo(repairRecord.getRecordNo());
                }
            }

            List<RepairRefundRecord> repairRefundRecords = new ArrayList<>();

//            报修人id
            Integer userId = rpr.getUserId();

//            名字
            if (ObjectUtils.isNotEmpty(users) && users.size() > 0) {
                for (RepairUser user : users) {
                    if (userId.equals(user.getId())) {
                        prrpv.setUserName(user.getUserName());
                    }
                }
            }


//            退款总金额
            BigDecimal refundPrice = BigDecimal.valueOf(0);
//            退款记录
            if (ObjectUtils.isNotEmpty(refundRecords) && refundRecords.size() > 0) {
                for (RepairRefundRecord refundRecord : refundRecords) {
                    if (recordId.equals(refundRecord.getRecordId())) {
                        repairRefundRecords.add(refundRecord);
                        refundPrice = refundPrice.add(refundRecord.getRefundPrice());
                    }
                }
            }
//      状态
            if (repairRefundRecords.size() > 0) {
                BigDecimal payPrice = rpr.getPayPrice();
//
                if (payPrice.compareTo(refundPrice) == 0) {
                    prrpv.setState(ePayPageStatu.Refunded.getValue());
                } else {
                    prrpv.setState(ePayPageStatu.Rebates.getValue());
                }
            } else {
                prrpv.setState(ePayPageStatu.HavePaid.getValue());
            }

            prrpv.setRepairRefundRecordList(repairRefundRecords);

            vos.add(prrpv);
        });

        prpr.setRecords(vos);

        return CommonResult.ok(prpr);
    }

    /**
     * 实退
     *
     * @return
     */
    @Override
    public CommonResult refundableAmount(RefundableAmountRequest rar, String userhead, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            String st = paramUtils.getParamError(bindingResult);
            return CommonResult.fail(st);
        }
//        超级管理员才有实退权限
        String userID = AesUtils.decrypt(userhead);
        RepairAdmin operateData = repairAdminService.getRepairById(userID);
        if (operateData == null && eIsSuper.Super.getValue() == operateData.getIsSuper()) {
            return CommonResult.fail("操作人权限不足，无法使用实退功能！");
        }


//      支付订单ID
        Integer repairPayRecordId = rar.getRepairPayRecordId();
//      退款金额
        BigDecimal refundPrice = rar.getRefundPrice();

        RepairPayRecord repairPayRecord = repairPayRecordService.getById(repairPayRecordId);

//        实退金额不能大于剩余金额
        Integer recordId = repairPayRecord.getRecordId();
//        实收金额
        BigDecimal payPrice = repairPayRecord.getPayPrice();
        LambdaQueryWrapper<RepairRefundRecord> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(RepairRefundRecord::getRecordId,recordId);
        List<RepairRefundRecord> refundRecordList = repairRefundRecordService.list(wrapper);
        BigDecimal refundTotal=new BigDecimal(0);
        for (RepairRefundRecord repairRefundRecord : refundRecordList) {
            BigDecimal refundPrice1 = repairRefundRecord.getRefundPrice();
            refundTotal=refundTotal.add(refundPrice1);
        }

//        实收金额减总退款金额在减实退金额，不能小于0
        int i = payPrice.subtract(refundTotal).subtract(refundPrice).compareTo(new BigDecimal(0));
        if (i<0) {
            return CommonResult.fail("实退金额有误");
        }

        RepairRefundRecord repairRefundRecord = new RepairRefundRecord();

        repairRefundRecord.setRecordId(repairPayRecord.getRecordId());
        repairRefundRecord.setUserId(repairPayRecord.getUserId());
        repairRefundRecord.setWxNo(repairPayRecord.getPayNo());
        repairRefundRecord.setRefundNo("ST"+ UUIDUtils.create());
        repairRefundRecord.setRefundPrice(refundPrice);
        repairRefundRecord.setIsSuccess(eIsSuccess.Succeed.getValue());
        repairRefundRecord.setRemark("实退");

        boolean save = repairRefundRecordService.save(repairRefundRecord);

        if (save) {
            return CommonResult.ok("实退成功");
        }

        return CommonResult.fail("实退失败");
    }

    /**
     * 统计
     * @return
     * @throws Exception
     */
    @Override
    public CommonResult statistics() throws Exception {
        LambdaQueryWrapper<RepairPayRecord> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(RepairPayRecord::getIsSuccess, eIsSuccess.Succeed.getValue());

        List<RepairPayRecord> payRecordList = repairPayRecordService.list(wrapper);
//        总金额
        BigDecimal totalPrice=new BigDecimal(0);
        for (RepairPayRecord repairPayRecord : payRecordList) {
            BigDecimal payPrice = repairPayRecord.getPayPrice();
            totalPrice=totalPrice.add(payPrice);
        }

        LambdaQueryWrapper<RepairRefundRecord> refundWrapper=new LambdaQueryWrapper<>();
        refundWrapper.eq(RepairRefundRecord::getIsSuccess, eIsSuccess.Succeed.getValue());
        List<RepairRefundRecord> list = repairRefundRecordService.list(refundWrapper);
        BigDecimal refundTotalPrice=new BigDecimal(0);
        for (RepairRefundRecord repairRefundRecord : list) {
            BigDecimal refundPrice = repairRefundRecord.getRefundPrice();
            refundTotalPrice=refundTotalPrice.add(refundPrice);
        }
        StatisticsVo statisticsVo = new StatisticsVo();
        statisticsVo.setCount(payRecordList.size());
        statisticsVo.setTotalPrice(totalPrice);
        statisticsVo.setRefundTotalPrice(refundTotalPrice);

        return CommonResult.ok(statisticsVo);
    }

    /**
     * 限制实退金额
     * @param payRecordId
     * @return
     * @throws Exception
     */
    @Override
    public CommonResult restrict(int payRecordId) throws Exception {

        RepairPayRecord payRecord = repairPayRecordService.getById(payRecordId);

        if (ObjectUtils.isEmpty(payRecord)) {
            return CommonResult.fail("参数异常");
        }
//        实付金额
        BigDecimal payPrice = payRecord.getPayPrice();

        Integer recordId = payRecord.getRecordId();

        LambdaQueryWrapper<RepairRefundRecord> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(RepairRefundRecord::getRecordId,recordId);

        List<RepairRefundRecord> refundRecordList = repairRefundRecordService.list(wrapper);
//      退款总金额
        BigDecimal refundTotalPrice=new BigDecimal(0);
        for (RepairRefundRecord repairRefundRecord : refundRecordList) {
            BigDecimal refundPrice = repairRefundRecord.getRefundPrice();
            refundTotalPrice=refundTotalPrice.add(refundPrice);
        }

        int i = payPrice.compareTo(refundTotalPrice);
        if (i>=0) {
            BigDecimal subtract = payPrice.subtract(refundTotalPrice);
            return CommonResult.ok(subtract);
        }

        return CommonResult.fail();
    }


    @Override
    public void queryExport(HttpServletResponse response, String keyWord, String startTime, String endTime) {

        if (startTime != null && endTime != null) {
            try {
                startTime = TimeExchange.getStartOfDayStr(TimeExchange.StringToDate(startTime, "yyyy-MM-dd"));
                endTime = TimeExchange.getEndOfDayStr(TimeExchange.StringToDate(endTime, "yyyy-MM-dd"));
            } catch (Exception e) {
            }
        }

        List<QueryExportVo> queryExportVoList=repairPayRecordService.queryExport(keyWord,startTime,endTime);

        List<QueryExportVo> vos = new ArrayList<>();


        //        导出
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("支付成功记录表");
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("序号");
        headerRow.createCell(1).setCellValue("交易时间");
        headerRow.createCell(2).setCellValue("工单号");
        headerRow.createCell(3).setCellValue("交易流水号");
        headerRow.createCell(4).setCellValue("报修人");
        headerRow.createCell(5).setCellValue("交易金额");
        headerRow.createCell(6).setCellValue("退款金额");
        headerRow.createCell(7).setCellValue("状态");


        if (ObjectUtils.isNotEmpty(queryExportVoList)&&queryExportVoList.size()>0) {

            for (QueryExportVo queryExportVo : queryExportVoList) {
                QueryExportVo vo = new QueryExportVo();
                BeanUtils.copyProperties(queryExportVo, vo);
//            退款金额
                BigDecimal refundTotalPrice = queryExportVo.getRefundTotalPrice();
                if (ObjectUtils.isEmpty(refundTotalPrice)) {
                    refundTotalPrice = new BigDecimal(0);
                    vo.setRefundTotalPrice(refundTotalPrice);
                }
                BigDecimal payPrice = queryExportVo.getPayPrice();
//            退款金额=0
                if (refundTotalPrice.compareTo(new BigDecimal(0)) == 0) {
                    vo.setStatus("已支付");
                } else if (payPrice.compareTo(refundTotalPrice) == 0) {
                    vo.setStatus("已退款");
                } else if (payPrice.compareTo(refundTotalPrice) == 1 && refundTotalPrice.compareTo(new BigDecimal(0)) == 1) {
                    vo.setStatus("部分退款");
                }

                vos.add(vo);
            }
            for (int i = 0; i < vos.size(); i++) {
                QueryExportVo vo = vos.get(i);
                Row dataRow1 = sheet.createRow(i + 1);
                dataRow1.createCell(0).setCellValue(vo.getId());
                dataRow1.createCell(1).setCellValue(vo.getPayTime());
                dataRow1.createCell(2).setCellValue(vo.getRecordNo());
                dataRow1.createCell(3).setCellValue(vo.getPayNo());
                dataRow1.createCell(4).setCellValue(vo.getUserName());
                dataRow1.createCell(5).setCellValue( vo.getPayPrice().toString());
                dataRow1.createCell(6).setCellValue( vo.getRefundTotalPrice().toString());
                dataRow1.createCell(7).setCellValue(vo.getStatus());
            }

        }

        // 将工作簿写入文件
        ExcelUtils.excelDownload(workbook, "支付成功表.xlsx", response);

    }
}

