package com.boco.nbd.wios.wx.controller;

import cn.hutool.core.lang.Assert;
import com.boco.nbd.cams.core.config.RedisClient;
import com.boco.nbd.wios.downloadfile.service.FileSupportService;
import com.boco.nbd.wios.manage.contants.WiosConstant;
import com.boco.nbd.wios.manage.entity.settlement.vo.InvoiceVo;
import com.boco.nbd.wios.manage.entity.bo.OrderVo;
import com.boco.nbd.wios.manage.entity.bo.UserLoginInfoVO;
import com.boco.nbd.wios.manage.service.impl.InvoiceService;
import com.boco.nbd.wios.manage.service.impl.OrderService;
import com.boco.nbd.wios.manage.service.impl.PushService;
import com.boco.nbd.wios.manage.service.impl.UserService;
import com.boco.nbd.wios.manage.util.NetUtil;
import com.boco.nbd.wios.manage.util.NumberUtil;
import com.boco.nbd.wios.manage.util.SpringContextUtil;
import com.boco.nbd.wios.wx.permisson.WxPermission;
import com.boco.nbd.wios.wx.service.WxOrderService;
import com.boco.nbd.wios.wx.vo.WxBillVO;
import com.boco.nbd.wios.wx.vo.WxInvoiceVO;
import com.boco.nbd.wios.wx.vo.WxOrderVO;
import com.boco.nbd.wios.wx.weixin.WeixinHelper;
import com.boco.nbd.wios.wx.weixin.WeixinSignUtils;
import com.ihidea.component.api.v2.BaseResponse;
import com.ihidea.core.support.exception.ServiceException;
import com.ihidea.core.util.StringUtilsEx;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author kevin
 * @create 2020/10/28 20:59
 */
@Api(tags = "微信公众号相关接口")
@WxPermission
@RestController
@RequestMapping("/wx")
@ApiIgnore
public class WeixinController {

    private static final Logger logger= LoggerFactory.getLogger(WeixinController.class);

    private static final String USER_LOGIN_CODE_CACHE_KEY="userLoginCode:";

    @Autowired
    private RedisClient redisClient;

    @Autowired
    private PushService pushService;

    @Autowired
    private UserService userService;

    @Autowired
    private OrderService orderService;

    @Autowired
    private WxOrderService wxOrderService;

    @Autowired
    private InvoiceService invoiceService;

    @Autowired
    private FileSupportService fileSupportService;


    @WxPermission(require = false)
    @GetMapping(value = "/getOpenIdByCode")
    @ApiOperation(value = "根据code获取openId")
    @ApiImplicitParams({@ApiImplicitParam(name = "code", value = "微信code", dataType = "String", paramType = "query", required = true)})
    public BaseResponse<String> getOpenIdByCode(String code) {
        String openId = null;
        if(StringUtils.isNotBlank(code)){
            openId = WeixinHelper.getOpenIdByCode(code);
        }
        return new BaseResponse<>(openId);
    }

    @GetMapping(value = "/getWxPrams")
    @ApiOperation(value = "获取微信签名参数")
    public BaseResponse<Object> getWxPrams() {
        return new BaseResponse<>(WeixinSignUtils.getParam());
    }

    private String checkSendPhoneMsgCode(String phone) {
        String ip= NetUtil.getIpAddr(SpringContextUtil.getRequest());
        String checkCacheKey="sendPhoneMsgCode:";

        //防止IP频繁请求(不能设置太长,存在同IP不同账户发送)
        if(!redisClient.getLock(checkCacheKey+"ip:"+ip, 30L)) {
            throw new ServiceException("请求频繁,请稍后");
        }

        // 防止手机号频繁发送请求
        if(!redisClient.getLock(checkCacheKey+"phone:"+phone, 60L)) {
            throw new ServiceException("请求频繁,请稍后");
        }

        return ip;
    }

    /**
     * 验证码的获取
     * @param phone
     * @throws Exception
     */
    @WxPermission(require = false)
    @ApiOperation("获取短信验证码")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "phone", value = "手机号", dataType = "String", paramType = "query", required = true),
            @ApiImplicitParam(name = "captcha", value = "图形验证码", dataType = "String", paramType = "query", required = false)
    })
    @PostMapping("/getPhoneMsgCode")
    public BaseResponse getCode(String phone, String captcha) throws Exception{

        logger.debug("请求短信验证码,手机号:"+phone);

        Assert.notBlank(phone, "手机号不能为空");

        checkSendPhoneMsgCode(phone);

        int code = NumberUtil.getRandomNum(1000, 9999);
        logger.debug("发送短信验证码,手机号:"+phone+","+code);
        pushService.sendUserLoginCode(phone, Integer.toString(code));
        // 20分钟内有效
        redisClient.put(USER_LOGIN_CODE_CACHE_KEY+phone, String.valueOf(code), 1200);

        return new BaseResponse();
    }

    @WxPermission(require = false)
    @ApiOperation("用户登录")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "phone", value = "手机号", dataType = "String", paramType = "query", required = true),
            @ApiImplicitParam(name = "smsCode", value = "短信验证码", dataType = "String", paramType = "query", required = true),
            @ApiImplicitParam(name = "openId", value = "微信openId", dataType = "String", paramType = "query", required = false)
    })
    @PostMapping("/login")
    public BaseResponse<UserLoginInfoVO> login(String phone, String smsCode, String openId){
        Assert.notBlank(phone, "手机号不能为空");
        Assert.notBlank(smsCode, "验证码不能为空");
        Assert.isTrue(StringUtils.equals(smsCode, redisClient.get(USER_LOGIN_CODE_CACHE_KEY+phone, String.class)),"验证码错误");

        UserLoginInfoVO userInfo = userService.login(phone, openId);
        redisClient.remove(USER_LOGIN_CODE_CACHE_KEY+phone);
        return new BaseResponse(userInfo);
    }

    @ApiOperation("用户登出")
    @PostMapping("/logout")
    public BaseResponse logout(){
        userService.logout();
        return new BaseResponse();
    }

    @ApiOperation("工单数量信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "phone", value = "手机号", dataType = "String", paramType = "query", required = true),
    })
    @GetMapping("/orderCountInfo")
    public BaseResponse userInfo(String phone){
        // 查询客户总工单数
        int orderCnt=orderService.countByCamsPhone(phone);
        String orderId="";
        if(orderCnt == 1){
            List<OrderVo> orderList=orderService.selectByCamsPhone(phone);
            if(CollectionUtils.isNotEmpty(orderList)){
                orderId = orderList.get(0).getId();
            }
        }

        Map<String, Object> result =new HashMap<>(2);
        result.put("orderCnt", orderCnt);
        result.put("orderId", orderId);

        return new BaseResponse(result);
    }

    @ApiOperation("安装工单列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "phone", value = "手机号", dataType = "String", paramType = "query", required = true),
    })
    @GetMapping("/orderList")
    public BaseResponse<List<WxOrderVO>> orderList(String phone){
        return new BaseResponse(wxOrderService.getList(phone));
    }

    @ApiOperation("安装工单详情")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "orderId", value = "工单编号", dataType = "String", paramType = "query", required = true),
    })
    @GetMapping("/orderDetail")
    public BaseResponse<WxOrderVO> orderDetail(String orderId){
        Assert.notBlank(orderId, "安装工单编号不能为空");
        return new BaseResponse(wxOrderService.getDetail(orderId));
    }



    @ApiOperation("安装订单列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "phone", value = "手机号", dataType = "String", paramType = "query", required = true),
    })
    @GetMapping("/billList")
    public BaseResponse<List<WxBillVO>> billList(String phone){
        return new BaseResponse(wxOrderService.getBillList(phone));
    }

    @ApiOperation("安装订单详情")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "orderId", value = "安装工单编号", dataType = "String", paramType = "query", required = true),
    })
    @GetMapping("/billDetail")
    public BaseResponse<WxBillVO> billDetail(String orderId){
        Assert.notBlank(orderId, "安装工单编号不能为空");
        return new BaseResponse(wxOrderService.getBillDetail(orderId));
    }


    @ApiOperation("安装订单支付")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "orderId", value = "工单编号", dataType = "String", paramType = "query", required = true),
            @ApiImplicitParam(name = "openId", value = "微信openId", dataType = "String", paramType = "query", required = true),
    })
    @GetMapping("/billPay")
    public BaseResponse billPay(String orderId, String openId){
        return new BaseResponse(wxOrderService.billPay(orderId, openId));
    }

    @ApiOperation("安装订单发票申请")
    @PostMapping("/billInvoiceApply")
    public BaseResponse billInvoiceApply(WxInvoiceVO wxInvoiceVO) throws Exception{
        invoiceService.applyInvoice(wxInvoiceVO);
        return new BaseResponse();
    }

    @ApiOperation("安装订单发票详情")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "billId", value = "工单账单编号", dataType = "String", paramType = "query", required = true),
    })
    @GetMapping("/billInvoiceDetail")
    public BaseResponse<WxInvoiceVO> billInvoiceDetail(String billId) throws Exception{
        Assert.notBlank(billId, "工单账单编号不能为空");
        InvoiceVo invoice = invoiceService.getInvoiceByBillId(billId);
        return new BaseResponse(invoice);
    }

    @ApiOperation("上传微信图片")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "mediaId", value = "多媒体编号,使用微信接口选择图片并上传到微信服务器后的serverId", dataType = "String", paramType = "query", required = true),
    })
    @GetMapping("/uploadImg")
    public BaseResponse<WxInvoiceVO> uploadImg(String mediaId) throws Exception{
        // 从微信服务器中下载图片
        byte[] content=WeixinHelper.getMediaContent(mediaId);
        // 将图片上传到OSS或本地图片服务器
        String fileId=fileSupportService.add(StringUtilsEx.getUUID() + ".jpg" , content, WiosConstant.OSS_DATA_STORE_NAME);
        return new BaseResponse(fileId);
    }

}