package com.younike.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.younike.common.core.domain.AjaxResult;
import com.younike.common.core.domain.entity.SysUser;
import com.younike.common.core.domain.model.LoginUser;
import com.younike.common.exception.GlobalException;
import com.younike.common.exception.ServiceException;
import com.younike.common.utils.SecurityUtils;
import com.younike.common.utils.StringUtils;
import com.younike.common.utils.bean.BeanUtils;
import com.younike.common.utils.id.MerchantIndexGenerate;
import com.younike.common.utils.sms.AliSmsUtil;
import com.younike.common.utils.sms.AliTemplateCode;
import com.younike.system.domain.*;
import com.younike.system.domain.vo.*;
import com.younike.system.enums.UserTypeEnum;
import com.younike.system.mapper.MerchantMapper;
import com.younike.system.mapper.SysUserMapper;
import com.younike.system.param.MerchantAuditParam;
import com.younike.system.param.MerchantQueryParam;
import com.younike.system.service.*;
import com.younike.wxpay.params.Amount;
import com.younike.wxpay.params.RefundParams;
import com.younike.wxpay.responses.RefundResponse;
import com.younike.wxpay.service.ISupplierPayService;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import static com.younike.common.utils.MoneyUtils.toCents;
import static com.younike.system.enums.MerchantStatusEnum.AUDITING;
import static com.younike.wxpay.utils.Contants.MASTER_REFUND_SUFFIX;
import static com.younike.wxpay.utils.Contants.SUB_REFUND_SUFFIX;
import static java.math.BigDecimal.ZERO;

/**
 * 店铺信息Service业务层处理
 *
 * @author elev
 * @date 2022-01-05
 */
@Service
@Log4j2
public class MerchantServiceImpl implements IMerchantService {
    @Autowired
    private MerchantMapper merchantMapper;
    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private IMerchantInfoService merchantInfoService;
    @Autowired
    private IMerchantBankService merchantBankService;
    @Autowired
    private IMerchantSettleInfoService merchantSettleInfoService;
    @Autowired
    private ISysRoleService sysRoleService;
    @Autowired
    private IOrderService orderService;
    @Autowired
    private AliSmsUtil smsUtil;
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private ISupplierPayService supplierPayService;
    @Autowired
    private IOrderPaymentService orderPaymentService;
    @Autowired
    private IOrderRefundService orderRefundService;
    @Autowired
    private IMemberService memberService;
    @Autowired
    private IMerchantService merchantService;
    @Autowired
    private ISysCodeService sysCodeService;
    @Autowired
    private IOrderRecordService orderRecordService;

    @Autowired
    private CoinService coinService;

    @Value("${domain}")
    private String domain;


    public final static int DEFAULT_PASSWORD_LENGTH = 6;
    public final static Long MERCHANT_ROLE_ID = 3L;

    /**
     * 检查是否修改的是自己的店铺
     * @param merchantId
     */
    @Override
    public void checkMerchant(Long merchantId){
        if (Objects.isNull(merchantId)){
            throw new RuntimeException("商户id不能为空");
        }
        Merchant merchant = selectMerchantByMerchantId(merchantId);
        if (Objects.isNull(merchant)){
            throw new RuntimeException("商户不存在或已被删除");
        }
        if (!merchant.getAdminId().equals(SecurityUtils.getUserId())){
            throw new RuntimeException("登录用户与商户所属账号不一致");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public MerchantSettledResultVO settled(MerchantSettledVO merchantSettledVO) {
        // 1. 注册用户并返回账号信息
        SysUser user = merchantSettledVO.getUser();
        String account = user.getPhonenumber();
        if (Objects.nonNull(sysUserService.selectUserByUserName(account))){
            throw new ServiceException("该手机已注册过账号，无法重复注册");
        }

        user.setUserName(account);
        String password = StringUtils.getCode(DEFAULT_PASSWORD_LENGTH);
        String userName = account.replaceAll("(\\\\d{3})\\\\d*(\\\\d{4})", "$1****$2");

        user.setPassword(SecurityUtils.encryptPassword(password));
        boolean isMerchant = 0 == merchantSettledVO.getMerchantType();
        user.setUserType(isMerchant ? UserTypeEnum.MERCHANT.getCode(): UserTypeEnum.PERSONAL.getCode());
        user.setEmail(account + "@yxx.com");
        sysUserService.registerUser(user);

        // 2. 店铺信息保存
        String createBy = user.getUserId().toString();
        merchantSettledVO.setAdminId(user.getUserId());
        BeanUtils.copyBeanProp(merchantSettledVO, merchantSettledVO.getAddress());
        if (StringUtils.isBlank(merchantSettledVO.getMerchantName())){
            merchantSettledVO.setMerchantName(account);
        }
        merchantSettledVO.setMerchantPhone(account);
        merchantSettledVO.setServerPhone(account);
        merchantSettledVO.setCreateBy(createBy);
        merchantSettledVO.setCreateTime(LocalDateTime.now());
        merchantSettledVO.setUpdateBy(createBy);
        merchantSettledVO.setUpdateTime(LocalDateTime.now());
        merchantSettledVO.setShopState(AUDITING.getCode());
        // 设置商家编号
        merchantSettledVO.setMerchantIndex(MerchantIndexGenerate.getIndexByMerchantType(merchantSettledVO.getMerchantType()));
        merchantMapper.insertMerchant(merchantSettledVO);

        Long merchantId = merchantSettledVO.getMerchantId();
        MerchantInfo merchantInfo = merchantSettledVO.getInfo();
        merchantInfo.setMerchantId(merchantId);
        merchantInfo.setCreateBy(createBy);
        merchantSettledVO.setCreateTime(LocalDateTime.now());
        merchantInfoService.insertMerchantInfo(merchantInfo);
        MerchantBank merchantBank = merchantSettledVO.getBank();
        merchantBank.setMerchantId(merchantId);
        merchantBank.setCreateBy(createBy);
        merchantSettledVO.setCreateTime(LocalDateTime.now());
        merchantBankService.insertMerchantBank(merchantBank);

        // 3. 账号密码短信通知并返回
        JSONObject param = new JSONObject();
        param.put("phone", userName);
        param.put("password", password);
        smsUtil.sendSms(account, param, AliTemplateCode.SETTLED_CODE);

        MerchantSettledResultVO result = new MerchantSettledResultVO();
        result.setUserName(userName);
        result.setPassword(password);
        return result;
    }

    @Override
    public int settledModify(MerchantSettledVO merchantSettledVO) {
        BeanUtils.copyBeanProp(merchantSettledVO, merchantSettledVO.getAddress());
        merchantInfoService.updateMerchantInfo(merchantSettledVO.getInfo());
        merchantBankService.updateMerchantBank(merchantSettledVO.getBank());
        merchantSettledVO.setShopState(AUDITING.getCode());
        return merchantMapper.updateMerchant(merchantSettledVO);
    }

    @Override
    public int merchantModify(MerchantModifyVO merchantModifyVO) {
        Merchant merchant = new Merchant();
        BeanUtils.copyBeanProp(merchant, merchantModifyVO);
        BeanUtils.copyBeanProp(merchant, merchantModifyVO.getAddress());
        // 修改联系人
        SysUser userUpdate = new SysUser();
        userUpdate.setUserId(merchantModifyVO.getUser().getUserId());
        userUpdate.setNickName(merchantModifyVO.getUser().getNickName());
        sysUserMapper.updateUser(userUpdate);
        return merchantMapper.updateMerchant(merchant);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean merchantRefund(MerchantRefundVO merchantRefund) {
        // 1. 验证合法性
        Merchant merchant = merchantService.selectMerchantByAdminId(SecurityUtils.getUserId());
        if (Objects.isNull(merchant)) {
            throw new ServiceException("请登录商家账号");
        }
        Long orderId = merchantRefund.getOrderId();
        if (Objects.isNull(orderId)){
            throw new ServiceException("订单id不能为空");
        }
        Order order = orderService.selectOrderByOrderId(orderId);
        if (Objects.isNull(order)){
            throw new ServiceException("订单不存在或已被删除");
        }
        if (!order.getMerchantId().equals(merchant.getMerchantId())){
            throw new ServiceException("订单商户与当前登录账号不一致");
        }
        if (Duration.between(order.getServiceEndTime(), LocalDateTime.now()).toHours() >= 24){
            throw new ServiceException("订单已超过24小时，不能退款");
        }
        BigDecimal refundMoney = merchantRefund.getRefundMoney();
        if (Objects.isNull(refundMoney) || refundMoney.compareTo(ZERO) <= 0){
            throw new ServiceException("退款金额不能为空, 且必须大于0");
        }
        if (refundMoney.compareTo(order.getTotalAmount()) > 0){
            throw new ServiceException("退款金额不能大于支付金额");
        }
        OrderRefund existRefund = orderRefundService.selectOrderRefundByOrderId(orderId.toString());
        if (Objects.nonNull(existRefund)){
            throw new ServiceException("同一笔订单只能申请一次退款");
        }

        // 2. 记录退款信息
        OrderRefund orderRefund = new OrderRefund();
        orderRefund.setOrderId(orderId);
        orderRefund.setPayMoney(refundMoney);
        orderRefund.setMome(merchantRefund.getRefundReason());
        orderRefund.setStatus("002");
        orderRefundService.insertOrderRefund(orderRefund);

        OrderRecord orderRecord = new OrderRecord();
        orderRecord.setOrderId(orderId);
        orderRecord.setPreState(order.getOrderState());
        orderRecord.setNowState("006");
        orderRecord.setOperateInfo(sysCodeService.getDecodeValue("003","006"));
        if (orderRecordService.insertOrderRecord(orderRecord) < 1) {
            throw new ArithmeticException("添加订单记录失败");
        }

        Order updateOrder = new Order();
        updateOrder.setOrderId(orderId);
        updateOrder.setOrderState("006");
        orderService.updateOrder(updateOrder);

        // 3. 退优金豆
        Member member = memberService.selectMemberByMemberId(order.getMemberId());
        if (Objects.isNull(member)) {
            throw new ServiceException("获取下单用户信息失败");
        }
        FamilyParam familyParam = new FamilyParam();
        familyParam.setTargetId(orderId.toString());    // 设置 关联id
        familyParam.setCode("002");            // 设置 积分变动类型（001-消费 002-退款 003-抵扣 004-评价订单新增）
        familyParam.setPhone(member.getPhone());
        familyParam.setOperation(merchant.getMerchantName());  // 设置 备注（商家名称）
        familyParam.setNum(new BigDecimal(-order.getBeanAmount()));    // 设置 扣除的积分数量
        String integralId = coinService.increasePoints(familyParam);
        if (StringUtils.isBlank(integralId)) {
            throw new ServiceException("退回优金豆失败");
        }

        // 4. 申请微信退款
        applyOrderRefund(order, refundMoney, orderRefund.getOrderRefundId());
        return true;
    }

    @Override
    public void applyOrderRefund(Order order, BigDecimal refundMoney, Long orderRefundId) {
        // 1 主订单退款
        OrderPayment orderPayment = orderPaymentService.selectOrderPaymentByOrderId(order.getOrderId());
        boolean isHomeService = "001".equals(order.getOrderType());
        BigDecimal addOrderAmount = Optional.ofNullable(
                isHomeService? order.getAddAmount(): order.getMaintenanceAmount()).orElse(ZERO);
        BigDecimal masterOrderAmount = order.getTotalAmount().subtract(addOrderAmount);
        BigDecimal subOrderRefund = refundMoney.subtract(masterOrderAmount);
        boolean needSubOrderRefund = subOrderRefund.compareTo(ZERO) > 0;
        String subMchid = merchantSettleInfoService.getMerchantNo(order.getMerchantId());
        RefundResponse masterRefundResponse = supplierPayService.refund(
                RefundParams.builder()
                        .sub_mchid(subMchid)
                        .transaction_id(orderPayment.getTransactionId())
                        .amount(Amount.refund(toCents(masterOrderAmount),
                                toCents(needSubOrderRefund? masterOrderAmount: refundMoney)))
                        .out_refund_no(orderRefundId + MASTER_REFUND_SUFFIX)
                        .notify_url(domain + "member/order/refund/cb")
                        .build());
        log.info("--------------------[主订单]申请微信退款结果：" + JSON.toJSONString(masterRefundResponse));
        if (!"PROCESSING".equals(masterRefundResponse.getStatus())){
            throw new ServiceException("--------------------[主订单]申请微信退款异常");
        }

        // 2 如果金额不够则申请子订单退款
        if (needSubOrderRefund) {
            RefundResponse subOrderResponse = supplierPayService.refund(
                    RefundParams.builder()
                            .sub_mchid(subMchid)
                            .transaction_id(isHomeService ? orderPayment.getAddTransactionId(): orderPayment.getManTransactionId())
                            .amount(Amount.refund(toCents(addOrderAmount), toCents(subOrderRefund)))
                            .out_refund_no(orderRefundId + SUB_REFUND_SUFFIX)
                            .notify_url(domain + "member/order/refund/cb")
                            .build());
            log.info("--------------------[子订单]申请微信退款结果：" + JSON.toJSONString(subOrderResponse));
            if (!"PROCESSING".equals(subOrderResponse.getStatus())){
                log.info("--------------------[子订单]申请微信退款异常");
            }
        }
    }

    @Override
    public Merchant selectMerchantByAdminId(Long adminId) {
        return merchantMapper.selectMerchantByAdminId(adminId);
    }

    /**
     * 查询店铺信息
     *
     * @param merchantId 店铺信息主键
     * @return 店铺信息
     */
    @Override
    public Merchant selectMerchantByMerchantId(Long merchantId) {
        Merchant merchant = merchantMapper.selectMerchantByMerchantId(merchantId);
        if (Objects.isNull(merchant)) {
            throw new ServiceException("商家不存在或已被删除");
        }
        return merchant;
    }

    /**
     * 查询店铺信息列表
     *
     * @param merchant 店铺信息
     * @return 店铺信息
     */
    @Override
    public List<Merchant> selectMerchantList(Merchant merchant) {
        return merchantMapper.selectMerchantList(merchant);
    }

    @Override
    public List<MerchantSettledVO> selectAuditMerchantList(MerchantQueryParam param) {
        return merchantMapper.selectAuditMerchantList(param);
    }

    @Override
    public List<MerchantSettledVO> selectPassMerchantList(MerchantQueryParam param) {
        return merchantMapper.selectPassMerchantList(param);
    }

    /**
     * 查询店铺入驻详情
     *
     * @param merchantId 店铺信息主键
     * @return 店铺信息
     */
    @Override
    public MerchantSettledVO merchantInfo(Long merchantId) {
        MerchantSettledVO merchantSettledVO = new MerchantSettledVO();
        Merchant merchant = merchantMapper.selectMerchantByMerchantId(merchantId);
        if (merchant != null) {
            BeanUtils.copyBeanProp(merchantSettledVO, merchant);
            if (merchant.getAdminId() != null) {
                merchantSettledVO.setUser(sysUserService.selectUserById(merchant.getAdminId()));
            }
            if (merchant.getExamineUser() != null) {
                // 查询审核人姓名
                SysUser examineUser = sysUserService.selectUserById(merchant.getExamineUser());
                merchantSettledVO.setExamineUserName(examineUser == null ? StringUtils.EMPTY : examineUser.getUserName());
            }
            MerchantInfo merchantInfo = merchantInfoService.selectMerchantInfoByMerchantId(merchantId);
            MerchantBank merchantBank = merchantBankService.selectMerchantBankByMerchantId(merchantId);
            SysUser user = sysUserService.selectSysUserById(merchant.getAdminId());
            merchantSettledVO.setInfo(merchantInfo == null ? new MerchantInfo() : merchantInfo);
            merchantSettledVO.setBank(merchantBank == null ? new MerchantBank() : merchantBank);
            merchantSettledVO.setUser(user);
            AddressVO address = new AddressVO();
            BeanUtils.copyBeanProp(address, merchant);
            merchantSettledVO.setAddress(address);
            // 查询商家微信账号
            MerchantSettleInfo settleInfo = merchantSettleInfoService.selectMerchantSettleInfoByMerchantId(merchantId);
            merchantSettledVO.setMerchantNo(settleInfo == null ? null : settleInfo.getMerchantNo());
        }
        return merchantSettledVO;
    }

    /**
     * 修改店铺信息
     *
     * @param merchant 店铺信息
     * @return 结果
     */
    @Override
    public int updateMerchant(Merchant merchant) {
        merchant.setUpdateTime(LocalDateTime.now());
        return merchantMapper.updateMerchant(merchant);
    }

    /**
     * 批量删除店铺信息
     *
     * @param merchantIds 需要删除的店铺信息主键
     * @return 结果
     */
    @Override
    public int deleteMerchantByMerchantIds(Long[] merchantIds) {
        return merchantMapper.deleteMerchantByMerchantIds(merchantIds);
    }

    /**
     * 删除店铺信息信息
     *
     * @param merchantId 店铺信息主键
     * @return 结果
     */
    @Override
    public int deleteMerchantByMerchantId(Long merchantId)
    {
        return merchantMapper.deleteMerchantByMerchantId(merchantId);
    }

    @Override
    public void updateMerchants(List<Merchant> merchantList) {
        merchantMapper.updateMerchants(merchantList);
    }

    @Override
    @Transactional
    public AjaxResult handleAudit(MerchantAuditParam auditParam) {
        if (auditParam == null || auditParam.getMerchantId() == null || org.apache.commons.lang3.StringUtils.isEmpty(auditParam.getShopState())) {
            return AjaxResult.error("参数错误");
        }
        String userName = "";
        Merchant merchant = new Merchant();
        merchant.setMerchantId(auditParam.getMerchantId());
        merchant.setShopState(auditParam.getShopState());
        try {
            LoginUser loginUser = SecurityUtils.getLoginUser();
            merchant.setUpdateBy(loginUser.getUsername());
            merchant.setUpdateTime(LocalDateTime.now());
            merchant.setExamineUser(loginUser.getUserId());
            userName = loginUser.getUsername();
        } catch (Exception e) {
            e.printStackTrace();
        }
        Merchant merchantByMerchantId = this.selectMerchantByMerchantId(auditParam.getMerchantId());
        if (merchantByMerchantId == null) {
            return AjaxResult.error("商家数据有误");
        }

        // 商家审核通过
        if (auditParam.getShopState().equals("002")) {
            if (merchantByMerchantId.getMerchantType() == 0) {
                if (StringUtils.isEmpty(auditParam.getMerchantNo())) {
                    return AjaxResult.error("微信账号不能为空");
                }
                MerchantSettleInfo merchantSettleInfo = new MerchantSettleInfo();
                merchantSettleInfo.setMerchantId(auditParam.getMerchantId());
                merchantSettleInfo.setMerchantNo(auditParam.getMerchantNo());
                SysUser user = sysUserService.selectSysUserById(merchantByMerchantId.getAdminId());
                if (user == null) {
                    return AjaxResult.error("获取用户信息失败");
                }
                if (StringUtils.isEmpty(user.getEmail())) {
                    return AjaxResult.error("获取用户邮箱失败");
                }
                // todo 设置邮箱
                merchantSettleInfo.setEmail(user.getEmail());

                MerchantSettleInfo settleInfo = merchantSettleInfoService.selectMerchantSettleInfoByMerchantId(auditParam.getMerchantId());
                if (settleInfo == null) {
                    merchantSettleInfo.setCreateBy(userName);
                    merchantSettleInfo.setCreateTime(LocalDateTime.now());
                    if (this.merchantSettleInfoService.insertMerchantSettleInfo(merchantSettleInfo) < 1) {
                        throw new GlobalException("编辑微信账户失败");
                    }
                } else {
                    merchantSettleInfo.setUpdateBy(userName);
                    merchantSettleInfo.setUpdateTime(LocalDateTime.now());
                    if (this.merchantSettleInfoService.updateMerchantSettleInfo(merchantSettleInfo) < 1) {
                        throw new GlobalException("修改微信账户失败");
                    }
                }
            }
            List<Long> roles = sysRoleService.selectRoleListByUserId(merchantByMerchantId.getAdminId());
            if (roles == null || !roles.contains(MERCHANT_ROLE_ID)) {
                if (sysRoleService.insertAuthUsers(MERCHANT_ROLE_ID, new Long[]{merchantByMerchantId.getAdminId()}) < 1) {
                    throw new GlobalException("编辑用户角色失败");
                }
            }
            // 审核通过，发送短信通知
            JSONObject param = new JSONObject();
            param.put("name", merchantByMerchantId.getMerchantName());
            param.put("phone", merchantByMerchantId.getMerchantPhone());
            param.put("result", "通过");
            smsUtil.sendSms(merchant.getMerchantPhone(), param, AliTemplateCode.MERCHANT_AUDIT_SUCCESS_CODE);
        }
        // 商家审核驳回
        if (auditParam.getShopState().equals("003")) {
            merchant.setExamineReason(auditParam.getExamineReason());
            // 审核驳回，发送短信通知
            smsUtil.sendSms(merchantByMerchantId.getMerchantPhone(), new JSONObject(), AliTemplateCode.MERCHANT_AUDIT_REJECTED_CODE);
        }
        merchant.setExamineTime(LocalDateTime.now());
        if (this.updateMerchant(merchant) < 1) {
            throw new GlobalException("修改商家信息失败");
        }

        return AjaxResult.success();
    }

    /**
     * 根据商家类型查询商户数量
     *
     * @param merchantType
     * @return
     */
    @Override
    public int getMerchantCountByMerchantType(String merchantType) {
        return merchantMapper.getMerchantCountByMerchantType(merchantType);
    }

    /**
     * 根据服务人员信息查询店铺信息
     *
     * @param serverId
     * @return
     */
    @Override
    public Merchant selectMerchantByServerId(Long serverId) {
        return merchantMapper.selectMerchantByServerId(serverId);
    }

    /**
     * 会员端： 商家主页
     *
     * @param merchantId
     * @return
     */
    @Override
    public Merchant getMerchantByMerchantId(Long merchantId) {
        Merchant merchant = this.selectMerchantByMerchantId(merchantId);
        if (ObjectUtils.isEmpty(merchant)) {
            throw new ArithmeticException("商家不存在");
        }
//        店铺状态 code 001审核中 002审核成功 003审核失败 004店铺下架
        if (!"002".equals(merchant.getShopState())) {
            throw new ArithmeticException("店铺审核为通过或店铺已下架");
        }
//        店铺营业状态  /** 营业状态 code 营业状态001营业中 002停止营业  */
        if (!"001".equals(merchant.getBusinessState())) {
            throw new ArithmeticException("店铺停止营业");
        }
        return merchant;
    }
}
