package com.app.service.order;

import com.app.constant.OrderConstant;
import com.app.constant.SystemConstant;
import com.app.dto.PageResult;
import com.app.dto.basics.operation.OpenCourseDto;
import com.app.dto.order.OpenCourseOrderDto;
import com.app.dto.order.operation.GenerateOrderDto;
import com.app.dto.order.search.SearchAdminOpenCourseOrderDto;
import com.app.dto.wx.PrePayDto;
import com.app.entity.BaseEntity;
import com.app.entity.basics.OpenCourse;
import com.app.entity.order.OpenCourseOrder;
import com.app.entity.order.OpenCourseOrderItem;
import com.app.entity.platform.system.AccountAuths;
import com.app.mapper.order.OpenCourseOrderItemMapper;
import com.app.mapper.order.OpenCourseOrderMapper;
import com.app.service.basics.OpenCourseService;
import com.app.service.platform.auth.AccountAuthsService;
import com.app.service.wx.WXPayService;
import com.app.service.wx.WXTemplateService;
import com.app.util.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

@Slf4j
@Service
public class OpenCourseOrderService {

    @Autowired
    private OpenCourseOrderMapper mapper;

    @Autowired
    private OpenCourseOrderItemMapper openCourseOrderItemMapper;

    @Autowired
    private AccountAuthsService accountAuthsService;

    @Autowired
    private OpenCourseService openCourseService;

    @Autowired
    private OpenCourseShoppingCarService openCourseShoppingCarService;

    @Autowired
    private OpenCourseOrderItemService openCourseOrderItemService;

    @Autowired
    private WXPayService wxPayService;

    @Autowired
    private WXTemplateService wXTemplateService;

    /**
     * 功能描述：查询[账号]底下的所有[订单]
     *
     * @param guardianId
     * @return
     */
    public PageResult<OpenCourseOrderDto> page(String guardianId, Integer page, Integer size) {
        IPage<OpenCourseOrder> _page = mapper.selectPage(new Page<>(page, size), new QueryWrapper<OpenCourseOrder>().lambda()
                .eq(OpenCourseOrder::getGuardianId, guardianId)
                .eq(BaseEntity::getIsDel, Boolean.FALSE)
                .orderByDesc(OpenCourseOrder::getId)
        );

        /* 对象转Dto */
        List<OpenCourseOrderDto> openCourseOrderDtoList = new ArrayList<>();
        for (OpenCourseOrder courseOrder : _page.getRecords()) {
            OpenCourseOrderDto dto = new OpenCourseOrderDto();
            BeanUtils.copyProperties(courseOrder, dto);
            dto.setOpenCourseOrderItemList(openCourseOrderItemService.list(courseOrder.getId(), courseOrder.getGuardianId()));
            openCourseOrderDtoList.add(dto);
        }

        return new PageResult(page, size, _page.getTotal(), openCourseOrderDtoList);
    }

    /**
     * 功能描述：查询所有订单
     *
     * @param param
     * @return
     */
    public PageResult<OpenCourseOrderDto> page(SearchAdminOpenCourseOrderDto param) {
        IPage<OpenCourseOrder> _page = mapper.findAllPage(param.getAccountId(), param.getTransactionId(), param.getChildName(), param.getPhoneNumber(),
                param.getSchoolId(), param.getSchoolYear(), param.getSemester(), param.getClassName(), param.getGradeName(), param.getOrderState(),param.getOrganIds(), new Page<>(param.getPage(), param.getSize()));

        /* 对象转Dto */
        List<OpenCourseOrderDto> openCourseOrderDtoList = new ArrayList<>();

        for (OpenCourseOrder courseOrder : _page.getRecords()) {
            OpenCourseOrderDto dto = new OpenCourseOrderDto();
            BeanUtils.copyProperties(courseOrder, dto);
            dto.setOpenCourseOrderItemList(openCourseOrderItemService.list(courseOrder.getId(), courseOrder.getGuardianId()));
            openCourseOrderDtoList.add(dto);
        }

        return new PageResult(param.getPage(), param.getSize(), _page.getTotal(), openCourseOrderDtoList);
    }

    public Optional<OpenCourseOrder> findById(String id) {
        OpenCourseOrder _openCourseOrder = mapper.selectById(id);
        return Optional.ofNullable(_openCourseOrder);
    }

    /**
     * 功能描述：查询[订单]详情
     *
     * @param orderId
     * @param guardianId
     * @return
     */
    public OpenCourseOrderDto find(String orderId, String guardianId) {
        OpenCourseOrderDto dto = new OpenCourseOrderDto();
        Optional<OpenCourseOrder> optional = findById(orderId);
        if (optional.isPresent()) {
            BeanUtils.copyProperties(optional.get(), dto);
            dto.setOpenCourseOrderItemList(openCourseOrderItemService.list(orderId, guardianId));
        }

        return dto;
    }

    /**
     * 功能描述：生成订单
     *
     * @param generateOrderDto
     * @param guardianId
     */
    @Transactional
    public OpenCourseOrder generate(GenerateOrderDto generateOrderDto, String guardianId) {
        /* 遍历购买的[开课]，并计算出总价格 */
        List<OpenCourse> openCourseList = openCourseService.findAllById(generateOrderDto.getOpenCourseIdList());
        for (OpenCourse openCourse : openCourseList) {
            if (openCourse.getFreeCourseNumber() <= 0) {
                throw new RuntimeException(String.format("[%s]课程，名额已满", openCourse.getName()));
            }
        }
        Double sumPrice = openCourseList.stream().mapToDouble(e -> e.getPrice()).sum();

        OpenCourseOrder openCourseOrder = new OpenCourseOrder();
        openCourseOrder.setWxmpFormId(generateOrderDto.getWxmpFormId());
        openCourseOrder.setPayablePrice(sumPrice); // 应付
        openCourseOrder.setRefund(0D); // 退款
        openCourseOrder.setPaidPrice(0D); // 实付
        openCourseOrder.setState(OrderConstant.OrderState.WAIT_PAY);
        openCourseOrder.setOrderExpireTime(DateUtil.plusMinutes(new Date(), SystemConstant.ORDER_TIME_EXPIRE));
        openCourseOrder = saveOrUpdate(openCourseOrder, guardianId);

        /* 遍历保存[订单项] */
        String orderId = openCourseOrder.getId();
        for (OpenCourse openCourse : openCourseList) {
            /* 课程的可用名额 -1 */
            openCourse.setFreeCourseNumber(openCourse.getFreeCourseNumber() - 1);
            OpenCourseDto dto = new OpenCourseDto();
            BeanUtils.copyProperties(openCourse, dto);
            openCourseService.saveOrUpdate(dto);

            OpenCourseOrderItem openCourseOrderItem = new OpenCourseOrderItem();
            openCourseOrderItem.setOpenCourseOrderId(orderId);
            openCourseOrderItem.setOpenCourseId(openCourse.getId());
            openCourseOrderItem.setGuardianChildId(generateOrderDto.getAccountChildId());
            openCourseOrderItem.setState(OrderConstant.OrderItemState.DEFAULT);
            openCourseOrderItemService.saveOrUpdate(openCourseOrderItem, guardianId);
        }

        return openCourseOrder;
    }

    public OpenCourseOrder saveOrUpdate(OpenCourseOrder openCourseOrder, String guardianId) {
        OpenCourseOrder _openCourseOrder;
        if (StringUtils.isEmpty(openCourseOrder.getId())) {
            _openCourseOrder = new OpenCourseOrder();
            _openCourseOrder.setGuardianId(guardianId);
            _openCourseOrder.setWxmpFormId(openCourseOrder.getWxmpFormId());
            _openCourseOrder.setPayablePrice(openCourseOrder.getPayablePrice()); // 应付
            _openCourseOrder.setOrderExpireTime(openCourseOrder.getOrderExpireTime());
            _openCourseOrder.setRefund(openCourseOrder.getRefund()); // 退款
            _openCourseOrder.setPaidPrice(openCourseOrder.getPaidPrice()); // 实付价格
            _openCourseOrder.setState(openCourseOrder.getState()); // 订单支付状态
            mapper.insert(_openCourseOrder);
        } else {
            _openCourseOrder = findById(openCourseOrder.getId()).get();
            _openCourseOrder.setRefund(openCourseOrder.getRefund()); // 退款
            _openCourseOrder.setPaidPrice(openCourseOrder.getPaidPrice()); // 实付价格
            _openCourseOrder.setState(openCourseOrder.getState()); // 订单支付状态
            mapper.updateById(_openCourseOrder);
        }

        return _openCourseOrder;
    }

    @Transactional
    public void delete(String orderId, String guardianId) {
        Optional<OpenCourseOrder> optional = findById(orderId);
        if (optional.isPresent()) {
            /* 把[订单]设置为删除状态 */
            OpenCourseOrder _openCourseOrder = optional.get();
            _openCourseOrder.setState(OrderConstant.OrderState.DELETED);
            mapper.updateById(_openCourseOrder);

            /* 课程的可用名额 +1 */
            for (OpenCourseOrderItem item : openCourseOrderItemService.list(orderId, guardianId)) {
                Optional<OpenCourse> optionalOpenCourse = openCourseService.findById(item.getOpenCourseId());
                if (optionalOpenCourse.isPresent()) {
                    OpenCourse openCourse = optionalOpenCourse.get();
                    openCourse.setFreeCourseNumber(openCourse.getFreeCourseNumber() + 1);
                    OpenCourseDto dto = new OpenCourseDto();
                    BeanUtils.copyProperties(openCourse, dto);
                    openCourseService.saveOrUpdate(dto);
                }
            }
        }
    }

    public void handleTimeoutOrder() {
        List<OpenCourseOrder> openCourseOrderList = mapper.selectList(new QueryWrapper<OpenCourseOrder>().lambda()
                .eq(OpenCourseOrder::getState, OrderConstant.OrderState.WAIT_PAY)
                .le(OpenCourseOrder::getOrderExpireTime, new Date())
        );
        for (OpenCourseOrder openCourseOrder : openCourseOrderList) {
            handleTimeoutOrder(openCourseOrder);
        }
    }

    @Transactional
    public void handleTimeoutOrder(OpenCourseOrder openCourseOrder) {
        /* 把[订单]设置为[超时]状态 */
        openCourseOrder.setState(OrderConstant.OrderState.TIMEOUT_PAY);
        mapper.updateById(openCourseOrder);

        /* 课程的可用名额 +1 */
        for (OpenCourseOrderItem item : openCourseOrderItemService.list(openCourseOrder.getId(), openCourseOrder.getGuardianId())) {
            Optional<OpenCourse> optionalOpenCourse = openCourseService.findById(item.getOpenCourseId());
            if (optionalOpenCourse.isPresent()) {
                OpenCourse openCourse = optionalOpenCourse.get();
                openCourse.setFreeCourseNumber(openCourse.getFreeCourseNumber() + 1);
                OpenCourseDto dto = new OpenCourseDto();
                BeanUtils.copyProperties(openCourse, dto);
                openCourseService.saveOrUpdate(dto);
            }
        }
    }

    /**
     * 功能描述：订单 - 预支付[微信支付]
     *
     * @param openId
     * @param orderId
     * @return
     */
    public PrePayDto payToStart(String guardianId, String openId, String orderId) {
        Optional<OpenCourseOrder> optional = findById(orderId);
        if (!optional.isPresent()) {
            throw new RuntimeException("");
        }

        List<OpenCourseOrderItem> itemList = openCourseOrderItemService.list(orderId, guardianId);
        String body = "430课程";
        String detail = "";
        if (itemList.size() > 1) {
            detail = String.format("%s 等共%s个课程", itemList.get(0).getName(), itemList.size());
        } else {
            detail = String.format("%s ", itemList.get(0).getName());
        }

        OpenCourseOrder _openCourseOrder = optional.get();
        BigDecimal totalFee = BigDecimal.valueOf(_openCourseOrder.getPayablePrice()); // 应付
        Date orderStartTime = Date.from(_openCourseOrder.getCreateAt().atZone( ZoneId.systemDefault()).toInstant());
        Date orderExpireTime = _openCourseOrder.getOrderExpireTime();

        /* 应付大于0，则走微信支付流程（生成签名预支付） */
        if (totalFee.compareTo(BigDecimal.ZERO) == 1) {
            return wxPayService.unifiedOrder(openId, orderId, body, detail, totalFee, orderStartTime, orderExpireTime);
        } else {
            PrePayDto prePayDto = new PrePayDto();
            prePayDto.setPaySign("hardcode");

            String transactionId = ""; // 微信支付订单号
            this.payToEnd(orderId, guardianId, transactionId, totalFee.doubleValue(), new Date());
            return prePayDto;
        }
    }

    /**
     * 功能描述：订单 - 支付成功[微信支付回调]
     *
     * @param orderId       订单标识
     * @param guardianId     账号标识
     * @param transactionId 微信支付订单号
     * @param paidPrice     实付价格
     * @param timeEnd       支付完成时间
     */
    @Transactional
    public void payToEnd(String orderId, String guardianId, String transactionId, Double paidPrice, Date timeEnd) {
        OpenCourseOrder _openCourseOrder = mapper.selectOne(new QueryWrapper<OpenCourseOrder>().lambda()
            .eq(OpenCourseOrder::getId, orderId)
            .eq(OpenCourseOrder::getGuardianId, guardianId)
        );
        if (!Optional.ofNullable(_openCourseOrder).isPresent()) {
            return;
        }

        /* 如果该[订单]已经设置为[已支付]则跳过 */
        if (OrderConstant.OrderState.SUCCESS_PAY.intValue() == _openCourseOrder.getState().intValue()) {
            return;
        }

        _openCourseOrder.setPaidPrice(paidPrice);
        _openCourseOrder.setState(OrderConstant.OrderState.SUCCESS_PAY);
        _openCourseOrder.setTransactionId(transactionId);
        _openCourseOrder.setPayEndTime(timeEnd);
        mapper.updateById(_openCourseOrder);

        /* 重置[选课单]的[开课]为[已支付]状态 */
        StringBuffer courseName = new StringBuffer();
        List<OpenCourseOrderItem> orderItemList = openCourseOrderItemService.list(orderId, guardianId);
        for (OpenCourseOrderItem item : orderItemList) {
            openCourseShoppingCarService.delete(item.getOpenCourseId(), _openCourseOrder.getGuardianId(), item.getGuardianChildId());
        }
        if (orderItemList.size() > 0) {
            courseName.append(orderItemList.get(0).getName());
        }
        if (orderItemList.size() > 1) {
            courseName.append(" 等");
        }

        /* 订阅消息通知 */
        try {
            Optional<AccountAuths> accountAuthsOptional = accountAuthsService.findWeixinMiniProgramByAccountId(_openCourseOrder.getGuardianId());
            if (accountAuthsOptional.isPresent()) {
                wXTemplateService.sendPaySuccessTemplate(accountAuthsOptional.get().getIdentifier(), _openCourseOrder.getId(), courseName.toString(), _openCourseOrder.getPaidPrice(), _openCourseOrder.getPayEndTime());
            }
        } catch(Exception e) {
            log.error("发送订阅消息失败，[{}]", e);
        }
    }

    public List<OpenCourseOrderItem> classByAccountId(String guardianId){
        return openCourseOrderItemMapper.myOpenCourse(guardianId, OrderConstant.OrderState.SUCCESS_PAY);
    }

}
