package com.api.controller.v1;

import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSONObject;
import com.hfkj.common.exception.ErrorCode;
import com.hfkj.common.exception.ErrorHelp;
import com.hfkj.common.exception.SysCode;
import com.hfkj.common.utils.*;
import com.hfkj.config.CommonSysConst;
import com.hfkj.entity.BsMer;
import com.hfkj.entity.BsTradeOrder;
import com.hfkj.entity.BsTradeOrderRefund;
import com.hfkj.model.ResponseData;
import com.hfkj.obs.HuaWeiYunObs;
import com.hfkj.openapi.v1.model.*;
import com.hfkj.openapi.v1.model.request.*;
import com.hfkj.openapi.v1.model.response.ResponseQueryTradeModel;
import com.hfkj.openapi.v1.model.response.ResponseRefundTradeModel;
import com.hfkj.openapi.v1.service.OpenApiTradeOrderService;
import com.hfkj.openapi.v1.utils.SignatureUtil;
import com.hfkj.service.BsMerKeyService;
import com.hfkj.service.BsMerService;
import com.hfkj.sysenum.*;
import com.obs.services.model.PutObjectResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.util.ResourceUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotBlank;
import java.io.File;
import java.math.BigDecimal;
import java.util.*;

@Controller
@Api(value = "交易订单")
@RequestMapping(value = "/v1/trade")
public class TradeController {

    private static Logger log = LoggerFactory.getLogger(TradeController.class);

    @Resource
    private BsMerKeyService merKeyService;
    @Resource
    private OpenApiTradeOrderService openApiTradeOrderService;
    @Resource
    private BsMerService merService;
    @Resource
    private RedisTemplate redisTemplate;

    @RequestMapping(value="/preorder",method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "聚合主扫")
    public ResponseData preorder(@Validated @RequestBody RequestTradePreorderModel body, HttpServletRequest request) {
        log.info("========= Start 聚合主扫接口 Start ===========");
        log.info("请求参数：" + JSONObject.toJSONString(body));
        try {
            // 验证签名
            if (!SignatureUtil.checkSign(body.getSign(), body, merKeyService.getKeyByMerNo(body.getMerchantNo()))) {
                throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_SIGN_ERR, "");
            }
            if (!body.getTransType().equals("JSAPI") && !body.getTransType().equals("NATIVE")) {
                throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "接入方式错误");
            }
            if (body.getTransType().equals("JSAPI") && StringUtils.isBlank(body.getUserId())) {
                throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "用户标识必填项");
            }
            // 查询支付方式
            TradeOrderPayModeEnum payMode = TradeOrderPayModeEnum.getNameByCode(body.getPayMode());
            if (payMode == null) {
                throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "支付方式错误");
            }
            // 查询商户
            BsMer mer = merService.getMer(body.getMerchantNo());
            if (mer == null) {
                throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "未知的商户号");
            }
            if (!mer.getMerStatus().equals(MerStatusEnum.status1.getNumber())) {
                throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "商户状态异常");
            }
            // 查询订单号是否存在
            BsTradeOrder outTradeNo = openApiTradeOrderService.getOrderByOutTradeNo(body.getOutTradeNo());
            if (outTradeNo != null) {
                throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "商户交易流水重复");
            }

            BsTradeOrder tradeOrder = new BsTradeOrder();
            tradeOrder.setTransType(body.getTransType());
            tradeOrder.setCompanyId(mer.getCompanyId());
            tradeOrder.setAgentId(mer.getAgentId());
            tradeOrder.setSalesmanId(mer.getSalesmanId());
            tradeOrder.setSalesmanName(mer.getSalesmanName());
            tradeOrder.setMerId(mer.getId());
            tradeOrder.setMerName(mer.getMerName());
            tradeOrder.setMerNo(mer.getMerNo());
            tradeOrder.setMerAbbreviate(mer.getMerAbbreviate());
            tradeOrder.setOutTradeNo(body.getOutTradeNo());
            tradeOrder.setTradeAmount(new BigDecimal(body.getTotalAmount()));
            tradeOrder.setTradeActualAmount(tradeOrder.getTradeAmount());
            tradeOrder.setPayMode(payMode.getCode());
            tradeOrder.setStatus(TradeOrderStatusEnum.status1.getNumber());
            tradeOrder.setProfitSharingStatus(body.getProfitSharing().equals("0")?false:true);
            tradeOrder.setCreateType(TradeOrderCreateTypeEnum.type3.getCode());
            tradeOrder.setPayAppid(body.getSubAppid());
            tradeOrder.setPayUserId(body.getUserId());
            tradeOrder.setTimeoutExpress(body.getTimeoutExpress());
            tradeOrder.setPayNotifyUrl(body.getNotifyUrl());
            tradeOrder.setSubject(body.getSubject());
            tradeOrder.setRefundPrice(new BigDecimal("0"));
            tradeOrder.setAttach(body.getAttach());
            tradeOrder.setSpecialField(body.getSpecialField());
            tradeOrder.setRequestIp(RequestUtils.getIpAddress(request));

            // 创建交易订单
            Map<String, Object> returnParam = openApiTradeOrderService.createOrder(tradeOrder);
            log.info("返回参数：" + JSONObject.toJSONString(returnParam));
            return ResponseMsgUtil.success(returnParam);

        } catch (Exception e) {
            log.info("出现异常：", e);
            return ResponseMsgUtil.exception(e);
        } finally {
            log.info("========= END 聚合主扫接口 END ===========");
        }
    }

    @RequestMapping(value="/queryTrade",method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "查询交易")
    public ResponseData queryTrade(@RequestBody RequestQueryTradeModel body) {
        log.info("========= Start 查询交易 Start ===========");
        log.info("请求参数：" + JSONObject.toJSONString(body));
        try {
            // 验证签名
            if (!SignatureUtil.checkSign(body.getSign(), body, merKeyService.getKeyByMerNo(body.getMerchantNo()))) {
                throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_SIGN_ERR, "");
            }
            // 查询交易订单号
            BsTradeOrder tradeOrder = openApiTradeOrderService.getOrderByOutTradeNo(body.getOutTradeNo());
            if (tradeOrder == null) {
                throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "未知的交易订单号");
            }

            ResponseQueryTradeModel responseQueryTradeModel = new ResponseQueryTradeModel();
            responseQueryTradeModel.setMerchantNo(tradeOrder.getMerNo());
            responseQueryTradeModel.setOutTradeNo(tradeOrder.getOutTradeNo());
            responseQueryTradeModel.setAccTradeNo(tradeOrder.getAccTradeNo());
            responseQueryTradeModel.setUserId(tradeOrder.getPayUserId());
            responseQueryTradeModel.setPayMode(tradeOrder.getPayMode());
            responseQueryTradeModel.setTradeAmount(tradeOrder.getTradeAmount());
            responseQueryTradeModel.setTradeActualAmount(tradeOrder.getTradeActualAmount());
            responseQueryTradeModel.setStatus(tradeOrder.getStatus());
            responseQueryTradeModel.setCreateTime(tradeOrder.getCreateTime());
            responseQueryTradeModel.setPayTime(tradeOrder.getPayTime());
            responseQueryTradeModel.setAttach(tradeOrder.getAttach());
            responseQueryTradeModel.setSign(SignatureUtil.createSign(responseQueryTradeModel, merKeyService.getKeyByMerNo(body.getMerchantNo())));

            log.info("返回参数：" + JSONObject.toJSONString(responseQueryTradeModel));
            return ResponseMsgUtil.success(responseQueryTradeModel);

        } catch (Exception e) {
            log.info("出现异常：", e);
            return ResponseMsgUtil.exception(e);
        } finally {
            log.info("========= END 查询交易 END ===========");
        }
    }

    @RequestMapping(value="/refund",method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "退款交易")
    public ResponseData refund(@Validated @RequestBody RequestRefundTradeModel body) {
        log.info("========= Start 退款交易接口 Start ===========");
        log.info("请求参数：" + JSONObject.toJSONString(body));
        try {
            // 验证签名
            if (!SignatureUtil.checkSign(body.getSign(), body, merKeyService.getKeyByMerNo(body.getMerchantNo()))) {
                throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_SIGN_ERR, "");
            }
            // 查询退款单号
            BsTradeOrderRefund refund = openApiTradeOrderService.getRefundByNo(body.getRefundTradeNo());
            if (refund != null) {
                throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "退款流水重复");
            }

            ResponseRefundTradeModel responseRefundTradeModel = openApiTradeOrderService.refund(body);
            log.info("返回参数：" + JSONObject.toJSONString(responseRefundTradeModel));
            return ResponseMsgUtil.success(responseRefundTradeModel);

        } catch (Exception e) {
            log.info("出现异常：", e);
            return ResponseMsgUtil.exception(e);
        } finally {
            log.info("========= END 退款交易接口 END ===========");
        }
    }

    @RequestMapping(value="/queryRefund",method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "查询退款")
    public ResponseData queryRefund(@RequestBody RequestQueryRefundModel body) {
        log.info("========= Start 查询退款 Start ===========");
        log.info("请求参数：" + JSONObject.toJSONString(body));
        try {
            // 验证签名
            if (!SignatureUtil.checkSign(body.getSign(), body, merKeyService.getKeyByMerNo(body.getMerchantNo()))) {
                throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_SIGN_ERR, "");
            }
            // 查询交易订单号
            BsTradeOrderRefund refund = openApiTradeOrderService.getRefundByNo(body.getRefundTradeNo());
            if (refund == null) {
                throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "未知的退款单号");
            }
            // 查询交易订单
            BsTradeOrder tradeOrder = openApiTradeOrderService.getOrderByOutTradeNo(refund.getOutTradeNo());
            if (tradeOrder == null) {
                throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "未知的交易订单");
            }
            ResponseRefundTradeModel refundTradeModel = new ResponseRefundTradeModel();
            refundTradeModel.setMerchantNo(tradeOrder.getMerNo());
            refundTradeModel.setOutTradeNo(tradeOrder.getOutTradeNo());
            refundTradeModel.setPayMode(tradeOrder.getPayMode());
            refundTradeModel.setRefundTradeNo(refund.getRefundNo());
            refundTradeModel.setAccTradeNo(refund.getAccTradeNo());
            refundTradeModel.setRefundAmount(refund.getRefundAmount().toString());
            refundTradeModel.setRefundPayerAmount(refund.getPayerAmount().toString());
            refundTradeModel.setRefundTime(refund.getRefundTime());
            refundTradeModel.setSign(SignatureUtil.createSign(refundTradeModel, merKeyService.getKeyByMerNo(tradeOrder.getMerNo())));
            log.info("返回参数：" + JSONObject.toJSONString(refundTradeModel));
            return ResponseMsgUtil.success(refundTradeModel);

        } catch (Exception e) {
            log.info("出现异常：", e);
            return ResponseMsgUtil.exception(e);
        } finally {
            log.info("========= END 查询退款 END ===========");
        }
    }

    @RequestMapping(value="/tradeBills",method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "账单下载")
    public ResponseData tradeBills(@RequestBody RequestTradeBillsModel body) {
        log.info("========= Start 账单下载 Start ===========");
        log.info("请求参数：" + JSONObject.toJSONString(body));
        try {
            // 验证签名
            if (!SignatureUtil.checkSign(body.getSign(), body, merKeyService.getKeyByMerNo(body.getMerchantNo()))) {
                throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_SIGN_ERR, "");
            }
            if (body.getBillDateS().compareTo(body.getBillDateE()) >= 0) {
                throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "开始时间必须小于结束时间");
            }
            // 最大周期范围3个月 90天
            Long maxTime = 60*24*90L;
            if (maxTime.compareTo(DateUtil.getMinutesDiff(new Date(body.getBillDateS()), new Date(body.getBillDateE()))) < 0) {
                throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "时间范围大于3个月");
            }

            List<TradeBillsModel> tradeBills = openApiTradeOrderService.tradeBills(body.getMerchantNo(), body.getBillDateS(), body.getBillDateE());
            String childPath = "temporary/";
            String fileName = System.currentTimeMillis() + "" + Math.abs(new Random().nextInt() % 1000) + ".xlsx";
            EasyExcel.write(CommonSysConst.getSysConfig().getFilesystem() + "/" + childPath + fileName, TradeBillsModel.class)
                    .sheet(body.getMerchantNo())
                    .doWrite(tradeBills);

            // 上传华为云 OBS
            HuaWeiYunObs.obsUtilPutObject(CommonSysConst.getSysConfig().getFilesystem() + "/" + childPath + fileName, HuaWeiYunObs.bucketName,  childPath + fileName);

            String fileUrl = CommonSysConst.getSysConfig().getObs_url() + "/"+ childPath + fileName;
            log.info("返回参数：" + fileUrl);
            return ResponseMsgUtil.success(fileUrl);
        } catch (Exception e) {
            log.info("出现异常：", e);
            return ResponseMsgUtil.exception(e);
        } finally {
            log.info("========= END 账单下载 END ===========");
        }
    }

    @RequestMapping(value="/tradeRefundBills",method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "账单退款下载")
    public ResponseData tradeRefundBills(@RequestBody RequestTradeRefundBillsModel body) {
        log.info("========= Start 账单退款下载 Start ===========");
        log.info("请求参数：" + JSONObject.toJSONString(body));
        try {
            // 验证签名
            if (!SignatureUtil.checkSign(body.getSign(), body, merKeyService.getKeyByMerNo(body.getMerchantNo()))) {
                throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_SIGN_ERR, "");
            }
            if (body.getBillDateS().compareTo(body.getBillDateE()) >= 0) {
                throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "开始时间必须小于结束时间");
            }
            // 最大周期范围3个月 90天
            Long maxTime = 60*24*90L;
            if (maxTime.compareTo(DateUtil.getMinutesDiff(new Date(body.getBillDateS()), new Date(body.getBillDateE()))) < 0) {
                throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "时间范围大于3个月");
            }

            List<TradeRefundBillsModel> tradeBills = openApiTradeOrderService.tradeRefundBills(body.getMerchantNo(), body.getBillDateS(), body.getBillDateE());
            String childPath = "temporary/";
            String fileName = System.currentTimeMillis() + "" + Math.abs(new Random().nextInt() % 1000) + ".xlsx";
            EasyExcel.write(CommonSysConst.getSysConfig().getFilesystem() + "/" + childPath + fileName, TradeRefundBillsModel.class)
                    .sheet(body.getMerchantNo())
                    .doWrite(tradeBills);

            // 上传华为云 OBS
            HuaWeiYunObs.obsUtilPutObject(CommonSysConst.getSysConfig().getFilesystem() + "/" + childPath + fileName, HuaWeiYunObs.bucketName,  childPath + fileName);

            String fileUrl = CommonSysConst.getSysConfig().getObs_url() + "/"+ childPath + fileName;
            log.info("返回参数：" + fileUrl);
            return ResponseMsgUtil.success(fileUrl);

        } catch (Exception e) {
            log.info("出现异常：", e);
            return ResponseMsgUtil.exception(e);
        } finally {
            log.info("========= END 账单退款下载 END ===========");
        }
    }

    @RequestMapping(value="/tradeSettleBills",method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "交易结算账单下载")
    public ResponseData tradeSettleBills(@RequestBody RequestTradeSettleBillsModel body) {
        log.info("========= Start 交易结算账单下载 Start ===========");
        log.info("请求参数：" + JSONObject.toJSONString(body));
        try {
            // 验证签名
            if (!SignatureUtil.checkSign(body.getSign(), body, merKeyService.getKeyByMerNo(body.getMerchantNo()))) {
                throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_SIGN_ERR, "");
            }
            // 最大周期范围1个月 31天
            Long maxTime = 60*24*31L;
            if (maxTime.compareTo(DateUtil.getMinutesDiff(new Date(body.getBillDateS()), new Date(body.getBillDateE()))) < 0) {
                throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "时间范围大于1个月");
            }

            Calendar billDateE = Calendar.getInstance();
            billDateE.setTime(new Date(body.getBillDateE()));
            billDateE.set(Calendar.HOUR_OF_DAY, 00);
            billDateE.set(Calendar.MINUTE, 00);
            billDateE.set(Calendar.SECOND, 00);

            // 当前时间
            Calendar currentDate = Calendar.getInstance();
            currentDate.set(Calendar.HOUR_OF_DAY, 00);
            currentDate.set(Calendar.MINUTE, 00);
            currentDate.set(Calendar.SECOND, 00);
            if (DateUtil.getMinutesDiff(billDateE.getTime(),currentDate.getTime()) <= 0) {
                currentDate.add(Calendar.DAY_OF_MONTH, -1);
                body.setBillDateE(currentDate.getTimeInMillis());
            }

            List<TradeDetailBillsModel> tradeBills = openApiTradeOrderService.tradeSettleBills(body.getMerchantNo(), body.getBillDateS(), body.getBillDateE());
            String childPath = "temporary/";
            String fileName = System.currentTimeMillis() + "" + Math.abs(new Random().nextInt() % 1000) + ".xlsx";
            EasyExcel.write(CommonSysConst.getSysConfig().getFilesystem() + "/" + childPath + fileName, TradeDetailBillsModel.class)
                    .sheet(body.getMerchantNo())
                    .doWrite(tradeBills);

            // 上传华为云 OBS
            HuaWeiYunObs.obsUtilPutObject(CommonSysConst.getSysConfig().getFilesystem() + "/" + childPath + fileName, HuaWeiYunObs.bucketName,  childPath + fileName);

            String fileUrl = CommonSysConst.getSysConfig().getObs_url() + "/"+ childPath + fileName;
            log.info("返回参数：" + fileUrl);
            return ResponseMsgUtil.success(fileUrl);

        } catch (Exception e) {
            log.info("出现异常：", e);
            return ResponseMsgUtil.exception(e);
        } finally {
            log.info("========= END 交易结算账单下载 END ===========");
        }
    }

}
