package com.jeequan.jeepay.pay.ctrl.webcashier;

import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentParser;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.ApiField;
import com.jeequan.jeepay.JeepayClient;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.*;
import com.jeequan.jeepay.core.utils.JeepayKit;
import com.jeequan.jeepay.core.utils.JsonKit;
import com.jeequan.jeepay.core.utils.SeqKit;
import com.jeequan.jeepay.db.entity.*;
import com.jeequan.jeepay.exception.JeepayException;
import com.jeequan.jeepay.model.DeviceInfo;
import com.jeequan.jeepay.model.JeepayObject;
import com.jeequan.jeepay.model.PayOrderCreateResModel;
import com.jeequan.jeepay.pay.ctrl.payorder.AbstractPayOrderController;
import com.jeequan.jeepay.pay.service.PayMchNotifyService;
import com.jeequan.jeepay.request.PayOrderCreateRequest;
import com.jeequan.jeepay.response.PayOrderCreateResponse;
import com.jeequan.jeepay.service.impl.*;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
* 便捷收银台controller
*
* @author xiaoyu
*
* @date 2023/3/1 17:27
*/
@Controller
@RequestMapping("/api/cashierPage")
public class CashierPageController extends AbstractPayOrderController {

    @Autowired private PayOrderService payOrderService;
    @Autowired private SysConfigService sysConfigService;
    @Autowired private PayMchNotifyService payMchNotifyService;
    @Autowired private MchAppService mchAppService;
    @Autowired private MchInfoService mchInfoService;
    @Autowired private MchPayPassageService mchPayPassageService;
    @Autowired private MchConfigService mchConfigService;
    @Autowired private MchStoreService mchStoreService;


    /** 跳转到页面 **/
    @GetMapping("/{appId}/{storeId}")
    public String toPage(@PathVariable("appId") String appId, @PathVariable("storeId") String storeId){

        try {

            request.setAttribute("appId", appId);
            request.setAttribute("storeId", storeId);
            // 应用ID、 门店ID 解码
            appId = JeepayKit.aesDecode(appId);
            storeId = JeepayKit.aesDecode(storeId);

            MchAppEntity mchAppEntity = mchAppService.getById(appId);
            MchInfo mchInfo = mchInfoService.getById(mchAppEntity.getMchNo());
            MchStore mchStore = mchStoreService.getById(storeId);

            // 查询商户收银台配置信息
            CashierConfig cashierConfig = mchConfigService.queryMchCashierConfigByDefault(mchAppEntity.getMchNo(), MchConfig.SELF_CASHIER_GROUP_KEY);

            if(cashierConfig.getState() != CS.YES){
                throw new BizException("商户未开通[便捷收银台]功能");
            }

            // 静态CDN地址
            setPublicCdnHost();

            request.setAttribute("cashierConfig", cashierConfig);
            request.setAttribute("mchName", mchInfo.getMchName());
            request.setAttribute("storeName", mchStore != null ? mchStore.getStoreName():"");

            DBOEMConfig oemConfig = sysConfigService.getOemConfig();

            // 得到所有的支付方式
            Set<String> allWaycode = new HashSet<>();
            mchPayPassageService.list(MchPayPassage.gw().eq(MchPayPassage::getMchNo, mchAppEntity.getMchNo()).eq(MchPayPassage::getAppId, mchAppEntity.getAppId()).eq(MchPayPassage::getState, CS.YES))
                    .stream().forEach( r -> allWaycode.add(r.getWayCode()));

            // 处理 wxH5支付方式 and aliwap支付方式。
            cashierConfig.processWacodesWithWxH5AndALiwap(allWaycode);

            // 放置jsAPI
            if(allWaycode.contains(CS.PAY_WAY_CODE.WX_JSAPI) || allWaycode.contains(CS.PAY_WAY_CODE.ALI_JSAPI) || allWaycode.contains(CS.PAY_WAY_CODE.YSF_JSAPI) ){
                allWaycode.add(CS.PAY_WAY_CODE.QR_CASHIER);
            }

            request.setAttribute("allWaycode", JSON.toJSONString(allWaycode));

            request.setAttribute("oemConfig", oemConfig);

            UserAgent userAgent = UserAgentParser.parse(request.getHeader("User-Agent"));
            if(userAgent.getPlatform().isMobile()){
                return "cashierPage/cashierPageH5";
            }
            return "cashierPage/cashierPage";

        } catch (BizException e) {
            logger.error("业务异常", e);
            request.setAttribute("errMsg", e.getMessage());
            return "cashierPage/error";

        } catch (Exception e) {
            logger.error("异常", e);
            request.setAttribute("errMsg", e.getMessage());
            return "cashierPage/error";
        }
    }

    /*  跳转到支付成功页面 **/
    @GetMapping("/paySuccess")
    public String toReturnSuccessPage(){
        // 静态CDN地址
        setPublicCdnHost();
        return "cashier/returnPage";
    }

    /** 支付方式的转换 **/
    @PostMapping ("/convertPayway/{appId}/{storeId}")
    @ResponseBody
    public ApiRes convertPayway(@PathVariable("appId") String appId, @PathVariable("storeId") String storeId){
        PayOrderCreateRequest request = new PayOrderCreateRequest();
        PayOrderCreateReqModelAddStoreId model = new PayOrderCreateReqModelAddStoreId();
        // 需要转换的支付方式
        appId = JeepayKit.aesDecode(appId);
        String wayCode = getValStringRequired("wayCode");
        // 需要的方式（url跳转 or 二维码展示）
        String payDataType = getValString("payDataType");
        // 买家备注
        String buyerRemark = getValString("buyerRemark");
        MchAppEntity mchAppEntity = mchAppService.getById(appId);

        if(StringUtils.isNotBlank(payDataType)){ // payDataType
            model.setChannelExtra(JsonKit.newJson("payDataType", payDataType).toString());
        }
        // 任意一种签名方式
//        model.setSignType(appSignType.get(0));
        // 支付方式
        model.setWayCode(wayCode);
        // 订单金额
        model.setAmount(getRequiredAmountL("amount"));
        // 商户订单号
        model.setMchOrderNo(SeqKit.genMhoOrderId());
        // 门店ID
        model.setStoreId(JeepayKit.aesDecode(storeId));
        // appId
        model.setAppId(appId);
        // 商户号
        model.setMchNo(mchAppEntity.getMchNo());
        // 货币代码
        model.setCurrency("CNY");
        model.setSubject("收银台订单 [" + mchAppEntity.getMchNo() + "]");
        model.setBody("收银台订单 [" + mchAppEntity.getMchNo() + "]");
        // 失效时间 15分钟 60 * 15
        String expiredTime = "900";
        model.setExpiredTime(expiredTime);

        model.setBuyerRemark(buyerRemark);
        DBApplicationConfig dbApplicationConfig = sysConfigService.getDBApplicationConfig();
//        model.setNotifyUrl(dbApplicationConfig.getMchSiteUrl() + "/api/anon/paytestNotify/payOrder"); //回调地址

        model.setPas(SysConfigService.PLATFORM_API_SECRET); // 通信秘钥
        request.setBizModel(model);



        // 判断是否 需要  h5 ==》 小程序

        CashierConfig cashierConfig = mchConfigService.queryMchCashierConfigByDefault(mchAppEntity.getMchNo(), MchConfig.SELF_CASHIER_GROUP_KEY);


        // 得到所有的支付方式
        Set<String> allWaycode = new HashSet<>();
        mchPayPassageService.list(MchPayPassage.gw().select(MchPayPassage::getWayCode)
                .eq(MchPayPassage::getMchNo, mchAppEntity.getMchNo()).eq(MchPayPassage::getAppId, mchAppEntity.getAppId()).eq(MchPayPassage::getState, CS.YES))
                .stream().forEach( r -> allWaycode.add(r.getWayCode()));

        // 商户可用 < 合并 > 配置
        List<String> wxH5PaywayListWithIntersectionDistinct = cashierConfig.getWxH5PaywayListWithIntersectionDistinct(allWaycode);
        List<String> aliWapPaywayListWithIntersectionDistinct = cashierConfig.getAliWapPaywayListWithIntersectionDistinct(allWaycode);

        // 微信H5支付方式  &&  配置的支付方式首先类型并不是 微信H5 , 那么需要做转换。
        if(CS.PAY_WAY_CODE.WX_H5.equals(wayCode) && !wxH5PaywayListWithIntersectionDistinct.isEmpty() && !wxH5PaywayListWithIntersectionDistinct.get(0).equals(CS.PAY_WAY_CODE.WX_H5)){

            // 微信小程序URL
            model.setChannelExtra(JsonKit.newJson("entryLiteType", QRCodeParams.ENTRY_LITE_WXH5).toString());
            model.setWayCode(CS.PAY_WAY_CODE.QR_CASHIER);
        }

        // 支付宝wap 支付方式  &&  配置的支付方式首先类型并不是 支付宝wap , 那么需要做转换。
        if(CS.PAY_WAY_CODE.ALI_WAP.equals(wayCode) && !aliWapPaywayListWithIntersectionDistinct.isEmpty() && !aliWapPaywayListWithIntersectionDistinct.get(0).equals(CS.PAY_WAY_CODE.ALI_WAP)){


            // 生活号的形式
            if(aliWapPaywayListWithIntersectionDistinct.get(0).equals(CS.PAY_WAY_CODE.ALI_JSAPI)){

                model.setChannelExtra(JsonKit.newJson("entryLiteType", QRCodeParams.ENTRY_LITE_ALIJSAPIH5).toString());
                model.setWayCode(CS.PAY_WAY_CODE.QR_CASHIER);

            }else{ // 支付宝小程序URL
                model.setChannelExtra(JsonKit.newJson("entryLiteType", QRCodeParams.ENTRY_LITE_ALIH5).toString());
                model.setWayCode(CS.PAY_WAY_CODE.QR_CASHIER);
            }
        }

        JeepayClient jeepayClient = new JeepayClient(dbApplicationConfig.getPaySiteUrl(), mchAppEntity.getAppSecret());

        try {
            PayOrderCreateResponse response = jeepayClient.execute(request);
            if(response.getCode() != 0){
                throw new BizException(response.getMsg());
            }

            // 存入下单超时时间
            PayOrderCreateResModel resModel = response.get();
            JSONObject resJson = (JSONObject) JSONObject.toJSON(resModel);
            resJson.put("expiredTime", expiredTime);
            return ApiRes.ok(resJson);
        } catch (JeepayException e) {
            throw new BizException(e.getMessage());
        }
    }


    /** 查单 **/
    @PostMapping("/orderState/{payOrderId}")
    @ResponseBody
    public ApiRes orderState(@PathVariable("payOrderId") String payOrderId){

        PayOrder payOrder = payOrderService.getById(payOrderId);

        JSONObject result = new JSONObject();
        result.put("state", payOrder.getState());

        // 支付成功
        if(payOrder.getState() == PayOrder.STATE_SUCCESS){

            // 包含同步回调地址
            if(StringUtils.isNotBlank(payOrder.getReturnUrl())){
                MchAppEntity mchAppEntity = mchAppService.getById(payOrder.getAppId());
                result.put("returnUrl", payMchNotifyService.createReturnUrl(payOrder, mchAppEntity.getAppSecret()));

            }else{
                result.put("returnUrl", "/api/cashierPage/paySuccess");
            }
        }

        return ApiRes.ok(result);
    }

    /** 与阿里云sdk一样，  直接extends PayOrderCreateReqModel无法传入到接口中对应的参数。 需要把所有的参数放进来。。。   = = 。   **/
    @Data
    public static class PayOrderCreateReqModelAddStoreId extends JeepayObject {

        @ApiField("pas")
        private String pas;

        @ApiField("storeId")
        private String storeId;

        private static final long serialVersionUID = -3998573128290306948L;

        @ApiField("mchNo")
        private String mchNo;      // 商户号
        @ApiField("appId")
        private String appId;      // 应用ID
        @ApiField("mchOrderNo")
        String mchOrderNo;          // 商户订单号
        @ApiField("wayCode")
        String wayCode;             // 支付方式
        @ApiField("amount")
        Long amount;                // 支付金额
        @ApiField("currency")
        String currency;            // 货币代码，当前只支持cny
        @ApiField("clientIp")
        String clientIp;            // 客户端IP
        @ApiField("subject")
        String subject;             // 商品标题
        @ApiField("body")
        String body;                // 商品描述
        @ApiField("channelBizData")
        String channelBizData;  // 渠道业务参数
        @ApiField("notifyUrl")
        String notifyUrl;           // 异步通知地址
        @ApiField("returnUrl")
        String returnUrl;           // 跳转通知地址
        @ApiField("expiredTime")
        String expiredTime;         // 订单失效时间
        @ApiField("channelExtra")
        String channelExtra;        // 特定渠道额外支付参数
        @ApiField("channelUser")
        String channelUser;         // 渠道用户标识,如微信openId,支付宝账号
        @ApiField("extParam")
        String extParam;            // 商户扩展参数
        @ApiField("divisionMode")
        private Byte divisionMode;   // 分账模式： 0-该笔订单不允许分账[默认], 1-支付成功按配置自动完成分账, 2-商户手动分账(解冻商户金额)
        @ApiField("sellerRemark")
        String sellerRemark;            // 卖家备注
        @ApiField("buyerRemark")
        String buyerRemark;            // 买家备注
        @ApiField("deviceInfo")
        private DeviceInfo deviceInfo;   // 设备信息

    }

    public void setPublicCdnHost(){
        // 静态CDN地址
        DBApplicationConfig dbApplicationConfig = sysConfigService.getDBApplicationConfig();
        request.setAttribute("staticCdnHost", dbApplicationConfig.getStaticCdnHost());
    }
}
