package com.izouma.nineth.web;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.anji.captcha.util.StringUtils;
import com.izouma.nineth.domain.DivMoney;
import com.izouma.nineth.domain.Order;
import com.izouma.nineth.domain.TransferMoneyInfo;
import com.izouma.nineth.domain.User;
import com.izouma.nineth.dto.DivMoneyDTO;
import com.izouma.nineth.dto.OrderDTO;
import com.izouma.nineth.dto.PageQuery;
import com.izouma.nineth.enums.*;
import com.izouma.nineth.exception.BusinessException;
import com.izouma.nineth.lock.RedisLockException;
import com.izouma.nineth.repo.DivMoneyRepo;
import com.izouma.nineth.repo.TransferMoneyInfoRepo;
import com.izouma.nineth.service.DivMoneyExecuteService;
import com.izouma.nineth.service.DivMoneyService;
import com.izouma.nineth.service.PayeasenetService;
import com.izouma.nineth.service.SandpayService;
import com.izouma.nineth.service.pay.UniformPayConstants;
import com.izouma.nineth.task.DivMoneyServiceTask;
import com.izouma.nineth.utils.ApplicationContextUtil;
import com.izouma.nineth.utils.excel.ExcelUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/divMoney")
@AllArgsConstructor
@Slf4j
public class DivMoneyController extends BaseController {

    /**
     * 一次分账限制数量
     */
    public static final Integer DIV_LIMIT_SIZE = 5000;

    //手动任务线程
    public static Thread runTaskThread = null;

    private DivMoneyService divMoneyService;

    private DivMoneyExecuteService divMoneyExecuteService;

    private TransferMoneyInfoRepo transferMoneyInfoRepo;

    private SandpayService sandpayService;

    private PayeasenetService payeasenetService;

    @PostMapping("/all")
    public Page<DivMoney> all(@RequestBody PageQuery pageQuery) {
        return divMoneyService.all(pageQuery);
    }

    @PostMapping("/excel")
    @ResponseBody
    public void excel(HttpServletResponse response, @RequestBody PageQuery pageQuery) throws IOException {
        List<DivMoney> data = all(pageQuery).getContent();
        ExcelUtils.export(response, data);
    }

    /**
     * 需要分账的数据
     * @param response
     * @param pageQuery
     * @throws IOException
     */
    @PostMapping("/checkDataExcel")
    @ResponseBody
    public void checkDataExcel(HttpServletResponse response, @RequestBody PageQuery pageQuery) throws IOException {
        List<DivMoneyDTO> dataList = divMoneyService.getCheckData(pageQuery);
        ExcelUtils.export(response, dataList);
    }

    /**
     * 导出杉德分账付款数据
     * @param response
     * @param pageQuery
     * @throws IOException
     */
    @PostMapping("/exportSandpayDiv")
    @ResponseBody
    public void exportSandpayDiv(HttpServletResponse response, @RequestBody PageQuery pageQuery) throws Exception {
        divMoneyService.exportSandpayDiv(pageQuery, response);
    }

    /**
     * 查询待标记数量
     * @return
     */
    @PostMapping("countBatchMark")
    public Long countBatchMark(@RequestBody PageQuery pageQuery){
        Long num = divMoneyService.countBatchMark(pageQuery);
        return num;
    }


    /**
     * 标记状态
     */
    @PostMapping("/markStatus")
    public void markStatus(@RequestBody JSONObject reqData){
        String status = reqData.getString("status");

        if(StringUtils.isEmpty(status)){
            throw new BusinessException("未指定更新状态");
        }
        DivStatus divStatus = DivStatus.valueOf(status);
        JSONObject jsonPage = reqData.getJSONObject("pageQuery");
        JSONArray ids = reqData.getJSONArray("ids");
        if(jsonPage != null){
            //批量更新
            PageQuery pageQuery = jsonPage.toJavaObject(PageQuery.class);
            divMoneyService.batchUpdateDivResult(pageQuery, divStatus);
        }else{
            //选择更新
            if(ids == null || ids.size() == 0){
                throw new BusinessException("未指定更新ID");
            }

            ids.stream().forEach(id -> {
                Long divMoneyId = Long.valueOf(id.toString());
                divMoneyService.updateDivStatus(divMoneyId, divStatus);
            });

        }




    }



    /**
     * 计算金额信息
     * @param pageQuery
     * @return
     */
    @PostMapping("calculateMoneyInfo")
    public Map<String,Object> calculateMoneyInfo(@RequestBody PageQuery pageQuery){
        Map<String,Object> result = divMoneyService.calculateMoneyInfo(pageQuery);
        return result;
    }




    /**
     * 手动调用开始自动分账
     *
     */
    @PreAuthorize("hasRole('ADMIN')")
    @PostMapping("batchDivMoney")
    public synchronized JSONObject batchDivMoney(@RequestBody PageQuery pageQuery){
        User user = currentUser();
        if(!ApplicationContextUtil.isHighestAdmin(user)){
            throw new BusinessException("只允许授权的管理员使用");
        }

        if(runTaskThread != null && runTaskThread.isAlive()){
            throw new BusinessException("任务正在进行，请稍后再试");
        }

        Long num = divMoneyService.countBatchMark(pageQuery);
        if(num > DIV_LIMIT_SIZE){
            throw new BusinessException("一次分账不能超过"+DIV_LIMIT_SIZE+"条记录，请更改查询条件");
        }

        JSONObject res = new JSONObject();
        final String batchNo = DateTimeFormatter.ofPattern("yyyyMMddHHmm").format(LocalDateTime.now());
        res.put("batchNo",batchNo);
        //获取分账数据，这里只会保留有效的数据
        List<DivMoneyDTO> dataList = divMoneyService.getCheckData(pageQuery);
        res.put("batchCount", dataList.size());

        runTaskThread = new Thread(() -> {
            log.info("手动分账数据， 数量：{} ", dataList.size());
            dataList.forEach(divMoneyDTO -> {
                if(divMoneyDTO.getUserId() == null){
                    return;
                }
                Long divMoneyId = Long.valueOf(divMoneyDTO.getId());
                try {
                    divMoneyExecuteService.executeDivMoney(divMoneyId, "批量手动分润", batchNo);
                }catch(Exception e){
                    divMoneyService.updateDivResult(divMoneyId, e.getMessage());
                    log.error("分账错误，分账ID:" + divMoneyDTO.getId() + ",原因：" +  e.getMessage());
                }

            });
        });

        runTaskThread.start();

        return res;

    }

    /**
     * 手动分账单笔记录
     * @return
     */
    @PreAuthorize("hasRole('ADMIN')")
    @PostMapping("executeDivMoney")
    public Object executeDivMoney(@RequestBody JSONObject reqData){
        User user = currentUser();
        if(!ApplicationContextUtil.isHighestAdmin(user)){
            throw new BusinessException("只允许授权的管理员使用");
        }

        Long divMoneyId = reqData.getLong("divMoneyId");
        if(divMoneyId == null){
            throw new BusinessException("分账ID不能为空");
        }

        try {
            TransferMoneyInfo transferMoneyInfo = divMoneyExecuteService.executeDivMoney(divMoneyId, "手动分润", null);

            return transferMoneyInfo;

        }catch(RedisLockException e){
            throw new BusinessException("操作过于频繁，请稍后再试");
        }

    }

    /**
     * 检查转账结果
     * @param reqData
     */
    @PreAuthorize("hasRole('ADMIN')")
    @PostMapping("checkTransferResult")
    public void checkTransferResult(@RequestBody JSONObject reqData) throws Exception{
        Long transferMoneyId = reqData.getLong("transferMoneyId");
        if(transferMoneyId == null){
            throw new BusinessException("转账ID不能为空");
        }

        divMoneyExecuteService.checkTransferResult(transferMoneyId);
    }


    /**
     * 查看转账记录
     * @param reqData
     * @return
     */
    @PreAuthorize("hasRole('ADMIN')")
    @PostMapping("viewTransferInfo")
    public TransferMoneyInfo viewTransferInfo(@RequestBody JSONObject reqData) throws Exception{
        Long transferMoneyId = reqData.getLong("transferMoneyId");
        if(transferMoneyId == null){
            throw new BusinessException("转账ID不能为空");
        }
        TransferMoneyInfo transferMoneyInfo = transferMoneyInfoRepo.findById(transferMoneyId).orElseThrow(new BusinessException("转账记录未找到"));
        //自动检查
        if(transferMoneyInfo.getStatus() == TransferStatus.PROCESSING){
            transferMoneyInfo = divMoneyExecuteService.checkTransferResult(transferMoneyId);
        }
        return transferMoneyInfo;
    }


    /**
     * 账户余额
     * @return
     */
    @PreAuthorize("hasRole('ADMIN')")
    @PostMapping("queryBalance")
    public Map<String,Object> querySandpayBalance(@RequestBody JSONObject reqData) throws Exception{
        String payPlatform = reqData.getString("payPlatform");
        Map<String,Object> balanceMap = new LinkedHashMap<>();
        if(UniformPayConstants.SANDPAY_PLATFORM.equals(payPlatform)){
            JSONObject res = sandpayService.queryBalance();
            BigDecimal balance = res.getBigDecimal("balance");
            BigDecimal creditAmt = res.getBigDecimal("creditAmt");

            balanceMap.put("balance", balance.divide(new BigDecimal(100), 2, RoundingMode.HALF_EVEN));
            balanceMap.put("creditAmt", creditAmt.divide(new BigDecimal(100), 2, RoundingMode.HALF_EVEN));
        }else if(UniformPayConstants.PAYEASENET_PLATFORM.equals(payPlatform)){
            JSONObject res = payeasenetService.queryBalance();
            BigDecimal availableTransferBalance = res.getBigDecimal("availableTransferBalance");
            balanceMap.put("balance", availableTransferBalance.divide(new BigDecimal(100), 2, RoundingMode.HALF_EVEN));
            balanceMap.put("creditAmt", availableTransferBalance.divide(new BigDecimal(100), 2, RoundingMode.HALF_EVEN));
        }else{
            throw new BusinessException("暂不支持该平台余额查询功能");
        }


        return balanceMap;
    }


}
