package com.gree.mall.miniapp.logic.order;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gree.mall.miniapp.bean.PayDetail;
import com.gree.mall.miniapp.bean.order.LeaseOrderBean;
import com.gree.mall.miniapp.bean.order.LeaseOrderVO;
import com.gree.mall.miniapp.bean.user.CurrentCompanyWechat;
import com.gree.mall.miniapp.commonmapper.CommonMapper;
import com.gree.mall.miniapp.enums.OrderInfoSourceEnum;
import com.gree.mall.miniapp.enums.PayTypeEnum;
import com.gree.mall.miniapp.exception.RemoteServiceException;
import com.gree.mall.miniapp.logic.common.CommonLogic;
import com.gree.mall.miniapp.logic.common.outside.WechatLogic;
import com.gree.mall.miniapp.plus.entity.*;
import com.gree.mall.miniapp.plus.service.*;
import com.gree.mall.miniapp.utils.IpUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class LeaseOrderLogic {

    private final CommonLogic commonLogic;
    private final CommonMapper commonMapper;
    private final LeaseOrderService leaseOrderService;
    private final LeaseOrderItemService leaseOrderItemService;
    private final LeaseOrderPayRecordService leaseOrderPayRecordService;
    private final GoodsLeaseService goodsLeaseService;
    private final WechatLogic wechatLogic;
    private final UserAddressService userAddressService;

    @Transactional
    public String add(LeaseOrderBean bean) {
        CurrentCompanyWechat wechat = commonLogic.getCurrentCompanyWechat();
        if (StringUtils.isBlank(bean.getUserAddressId())) {
            throw new RemoteServiceException("请选择收货地址");
        }
        final UserAddress userAddress = userAddressService.lambdaQuery()
                .eq(UserAddress::getCompanyWechatId, wechat.getCurrentCompanyWechatId())
                .eq(UserAddress::getUserAddressId, bean.getUserAddressId())
                .one();
        if (Objects.isNull(userAddress)) {
            throw new RemoteServiceException("收货地址信息异常");
        }
        if (CollectionUtil.isEmpty(bean.getItems())) {
            throw new RemoteServiceException("商品信息不能为空");
        }
        LeaseOrderItem orderItem = bean.getItems().get(0);
        if (Objects.isNull(orderItem.getStartDate())) {
            throw new RemoteServiceException("请选择租赁开始日期");
        }
        final DateTime curTimeDate = DateUtil.parseDate(DateUtil.formatDate(DateUtil.date()));
        if (orderItem.getStartDate().getTime() < curTimeDate.getTime()) {
            throw new RemoteServiceException("租赁开始日期必须大于等于当前日期");
        }
        if (Objects.isNull(orderItem.getGoodsLeaseId())) {
            throw new RemoteServiceException("租赁商品不能为空");
        }
        if (Objects.isNull(orderItem.getEndDate())) {
            throw new RemoteServiceException("请选择租赁结束日期");
        }
        if (orderItem.getStartDate().getTime() > orderItem.getEndDate().getTime()) {
            throw new RemoteServiceException("租赁开始日期不能大于租赁结束日期");
        }
        if (Objects.isNull(orderItem.getQty()) || orderItem.getQty() <= 0) {
            throw new RemoteServiceException("数量异常");
        }

        final GoodsLease goodsLease = goodsLeaseService.lambdaQuery()
                .eq(GoodsLease::getCompanyWechatId, wechat.getUser().getCompanyWechatId())
                .eq(GoodsLease::getId, orderItem.getGoodsLeaseId())
                .eq(GoodsLease::getStatus, true)
                .last("limit 1")
                .one();

        if (Objects.isNull(goodsLease)) {
            throw new RemoteServiceException("租赁商品信息不存在，请检查");
        }

        final String id = commonLogic.generateNo("ZP", "LEASE_ORDER", 13);
        BigDecimal bookAmount = BigDecimal.ZERO;

        orderItem.setLeaseOrderId(id)
                .setCompanyWechatId(wechat.getUser().getCompanyWechatId())
                .setCompanyWechatName(wechat.getUser().getCompanyName())
                .setCategoryId(goodsLease.getCategoryId())
                .setCategoryName(goodsLease.getCategoryName())
                .setCategoryUrl(goodsLease.getCategoryUrl())
                .setGoodsLeaseName(goodsLease.getName())
                .setGoodsUnit(goodsLease.getUnit())
                .setDepositPrice(goodsLease.getDepositPrice())
                .setLeasePrice(goodsLease.getLeasePrice())
                .setRepairRemark(goodsLease.getRepairRemark())
                .insert();

        bookAmount = bookAmount.add(orderItem.getDepositPrice().multiply(BigDecimal.valueOf(orderItem.getQty())));


        bean.setId(id)
                .setOnLineBill(true)
                .setCompanyWechatId(wechat.getUser().getCompanyWechatId())
                .setCompanyWechatName(wechat.getUser().getCompanyName())
                .setUserId(wechat.getUserId())
                .setUserName(wechat.getUser().getNickName())
                .setUserMobile(wechat.getUser().getMobile())
                .setUserAddress(userAddress.getAddress())
                .setProvinceId(userAddress.getProvinceId())
                .setAreaId(userAddress.getAreaId())
                .setCityId(userAddress.getCityId())
                .setStreetId(userAddress.getStreetId())
                .setProvince(userAddress.getProvince())
                .setArea(userAddress.getArea())
                .setCity(userAddress.getCity())
                .setStreet(userAddress.getStreet())
                .setPayType(PayTypeEnum.WECHAT.getKey())
                .setPayStatus(false)
                .setBookAmount(bookAmount)
                .setStatus("WAIT")
                .insert();
        return id;
    }

    public IPage<LeaseOrderVO> page(String keyword, Boolean payStatus, String status, Integer pageNum, Integer pageSize) {
        CurrentCompanyWechat wechat = commonLogic.getCurrentCompanyWechat();
        Boolean isEndDate = false;
        if ("OVER,RECOVER".contains(status)) {
            isEndDate = true;
        }
        final IPage<LeaseOrderVO> page = commonMapper.leaseOrderList(new Page<>(pageNum, pageSize), wechat.getUserId(), keyword, payStatus, status, isEndDate);
        return page;
    }

    @Transactional
    public PayDetail pay(HttpServletRequest request, String leaseOrderId, Boolean miniPay, String openId, Date realEndDate, String remark) {
        String ip = IpUtil.getIpAddr(request);
        CurrentCompanyWechat wechat = commonLogic.getCurrentCompanyWechat(request);
        LeaseOrder order = leaseOrderService.lambdaQuery()
                .eq(LeaseOrder::getId, leaseOrderId)
                .eq(LeaseOrder::getUserId, wechat.getUserId())
                .one();

        if (Objects.isNull(order)) {
            throw new RemoteServiceException(leaseOrderId + "订单号不存在，无法发起支付");
        }
        final LeaseOrderItem item = leaseOrderItemService.lambdaQuery()
                .eq(LeaseOrderItem::getLeaseOrderId, order.getId())
                .last("limit 1")
                .one();

        BigDecimal payValue;
        if (miniPay != null && miniPay) {
            leaseOrderService.lambdaUpdate()
                    .eq(LeaseOrder::getId, leaseOrderId)
                    .set(LeaseOrder::getSource, OrderInfoSourceEnum.A.getRemark())
                    .update();
        }else {
            leaseOrderService.lambdaUpdate()
                    .eq(LeaseOrder::getId, leaseOrderId)
                    .set(LeaseOrder::getSource, OrderInfoSourceEnum.B.getRemark())
                    .update();
        }

        if (!order.getPayStatus() && order.getStatus().equals("WAIT")) {
            payValue = order.getBookAmount();
            LeaseOrderPayRecord record = new LeaseOrderPayRecord();
            record.setCompanyWechatId(order.getCompanyWechatId())
                    .setCompanyWechatName(order.getCompanyWechatName())
                    .setLeaseOrderId(order.getId())
                    .setOrderType("FIRST")
                    .setUserId(order.getUserId())
                    .setPayValue(order.getBookAmount())
                    .setPayStatus(false)
                    .setSort(1)
                    .setOutTradeNo(leaseOrderId + "-" + record.getSort())
                    .setRenewalPrice(item.getRenewalPrice());

            if (order.getBookAmount().compareTo(BigDecimal.ZERO) <= 0) {
                record.setPayStatus(true)
                        .setStartDate(item.getStartDate())
                        .setEndDate(item.getEndDate())
                        .insert();
                order.setPayStatus(true)
                        .updateById();
                PayDetail payDetail = new PayDetail();
                payDetail.setIsPay(false);

                return payDetail;
            }

            record.insert();

            leaseOrderId = record.getOutTradeNo();
        } else if ((order.getStatus().equals("LEASE") || order.getStatus().equals("OVER")) && order.getPayStatus()) {
            if (Objects.isNull(realEndDate)) {
                throw new RemoteServiceException("请选择续租结束日期");
            }
            final Integer count = leaseOrderPayRecordService.lambdaQuery()
                    .eq(LeaseOrderPayRecord::getLeaseOrderId, order.getId())
                    .count();

            final LeaseOrderPayRecord renewalRecord = leaseOrderPayRecordService.lambdaQuery()
                    .eq(LeaseOrderPayRecord::getOrderType, "RENEWAL")
                    .eq(LeaseOrderPayRecord::getPayStatus, true)
                    .orderByDesc(LeaseOrderPayRecord::getCreateTime)
                    .last("LIMIT 1")
                    .one();

            if (Objects.nonNull(renewalRecord) && renewalRecord.getEndDate().after(DateUtil.date())) {
                throw new RemoteServiceException("上次续租日期未到期，请到期后操作");
            }

            // 当前单据的过期日期
            Date orderDate = Objects.isNull(item.getRealEndDate()) ? item.getEndDate() : item.getRealEndDate();
            if (realEndDate.getTime() <= orderDate.getTime()) {
                throw new RemoteServiceException("续租结束日期必须大于到期日期");
            }

            // 续租总租金=数量*续租单价/30天*（实际到期日期-到期日期）
            long leaseDay = DateUtil.betweenDay(orderDate, realEndDate, true);

            payValue = BigDecimal.valueOf(item.getQty())
                        .multiply(item.getRenewalPrice())
                        .divide(BigDecimal.valueOf(30L), 2, BigDecimal.ROUND_HALF_UP)
                        .multiply(BigDecimal.valueOf(leaseDay));

            payValue = payValue.compareTo(BigDecimal.ZERO) <= 0 ? item.getRenewalPrice().multiply(BigDecimal.valueOf(leaseDay)) : payValue;

            payValue = payValue.compareTo(BigDecimal.ZERO) <= 0 ? item.getRenewalPrice() : payValue;

            if (payValue.compareTo(BigDecimal.ZERO) <= 0) {
                throw new RemoteServiceException("续租金额计算为0，续租支付失败");
            }

            LeaseOrderPayRecord record = new LeaseOrderPayRecord();
            record.setCompanyWechatId(order.getCompanyWechatId())
                    .setCompanyWechatName(order.getCompanyWechatName())
                    .setLeaseOrderId(order.getId())
                    .setPayValue(payValue)
                    .setOrderType("RENEWAL")
                    .setUserId(order.getUserId())
                    .setStartDate(DateUtil.offsetDay(orderDate, 1))
                    .setEndDate(realEndDate)
                    .setPayStatus(false)
                    .setSort(count)
                    .setRemark(remark)
                    .setOutTradeNo(leaseOrderId + "-" + record.getSort())
                    .setRenewalPrice(item.getRenewalPrice())
                    .insert();
            leaseOrderId = record.getOutTradeNo();
        } else {
            throw new RemoteServiceException("租赁商品支付场景未定义");
        }
        return wechatLogic.payment(leaseOrderId, payValue, miniPay != null && miniPay? openId : wechat.getUser().getOpenId(), "N", ip, order.getCompanyWechatId(), miniPay);
    }

    public BigDecimal computeRenewalAmount(String id, Date realEndDate) {
        final LeaseOrderItem item = leaseOrderItemService.lambdaQuery()
                .eq(LeaseOrderItem::getLeaseOrderId, id)
                .last("limit 1")
                .one();
        Date orderDate = Objects.isNull(item.getRealEndDate()) ? item.getEndDate() : item.getRealEndDate();

        // 续租总租金=数量*续租单价/30天*（实际到期日期-到期日期）
        long leaseDay = DateUtil.betweenDay(orderDate, realEndDate, true);

        BigDecimal amount = BigDecimal.valueOf(item.getQty())
                .multiply(item.getRenewalPrice())
                .divide(BigDecimal.valueOf(30L), 2, BigDecimal.ROUND_HALF_UP)
                .multiply(BigDecimal.valueOf(leaseDay));

        amount = amount.compareTo(BigDecimal.ZERO) <= 0 ? item.getRenewalPrice().multiply(BigDecimal.valueOf(leaseDay)) : amount;

        return amount.compareTo(BigDecimal.ZERO) <= 0 ? item.getRenewalPrice() : amount;
    }

    public LeaseOrderBean detail(String id) {
        final LeaseOrder order = leaseOrderService.getById(id);
        LeaseOrderBean bean = new LeaseOrderBean();
        BeanUtils.copyProperties(order, bean);

        final List<LeaseOrderItem> items = leaseOrderItemService.lambdaQuery()
                .eq(LeaseOrderItem::getLeaseOrderId, id)
                .list();
        bean.setItems(items);

        final List<LeaseOrderPayRecord> records = leaseOrderPayRecordService.lambdaQuery()
                .eq(LeaseOrderPayRecord::getLeaseOrderId, id)
                .eq(LeaseOrderPayRecord::getPayStatus, true)
                .list();
        if (CollectionUtil.isNotEmpty(records)) {
            final List<LeaseOrderPayRecord> payRecords = records.stream().filter(v -> v.getOrderType().equals("FIRST")).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(payRecords)) {
                bean.setRecord(payRecords.get(0));
            }
            final List<LeaseOrderPayRecord> recordList = records.stream().filter(v -> !v.getOrderType().equals("FIRST")).collect(Collectors.toList());
            bean.setRecords(recordList);
        }

        return bean;
    }
}
