package com.ghy.quartz.service.impl;

import com.ghy.common.enums.OrderStatus;
import com.ghy.order.domain.OrderDetail;
import com.ghy.order.domain.OrderMaster;
import com.ghy.order.service.OrderDetailService;
import com.ghy.order.service.OrderMasterService;
import com.ghy.payment.domain.FinancialDetail;
import com.ghy.payment.domain.FinancialMaster;
import com.ghy.payment.domain.OrderTimeoutRecord;
import com.ghy.payment.mapper.OrderFineRecordMapper;
import com.ghy.payment.service.FinancialDetailService;
import com.ghy.payment.service.FinancialMasterService;
import com.ghy.quartz.service.OrderService;
import com.ghy.system.domain.SysDeptConfig;
import com.ghy.system.service.ISysDeptConfigService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

    private static final Integer ZERO = 0;
    private static final Integer ONE = 1;
    private static final Integer TWO = 2;

    /**
     * 需要超时扣款的订单状态
     *
     * @see OrderStatus
     */
    @Value("${order.timeout.status:-4,-3,-2,0,1,2,3}")
    private List<Integer> timeoutOrderStatus;
    private static final List<Integer> orderMasterTimeoutStatus = Arrays.asList(0, 1);

    @Resource
    private ThreadPoolTaskExecutor executor;
    @Resource
    private OrderMasterService orderMasterService;
    @Resource
    private OrderDetailService orderDetailService;
    @Resource
    private OrderFineRecordMapper orderFineRecordMapper;
    @Resource
    private FinancialDetailService financialDetailService;
    @Resource
    private FinancialMasterService financialMasterService;
    @Resource
    private ISysDeptConfigService sysDeptConfigService;

    @Override
    public void overTimeOrder(String orderStatus) {
        LocalTime nowT = LocalTime.now();
        // 晚上19点后 - 早上8点前不需要执行定时器
        if (nowT.getHour() < 8 || nowT.getHour() > 18) {
            return;
        }
        // 查询待接单状态的主单
        List<OrderMaster> orderMasters = orderMasterService.selectByStatus(orderMasterTimeoutStatus);
        log.info("扫描到{}条未完成的主订单", orderMasters.size());
        for (OrderMaster orderMaster : orderMasters) {
            executor.execute(() -> checkTimeout(orderMaster));
        }

        // 查询符合超时的子单
        List<OrderDetail> orders = orderDetailService.selectByStatus(timeoutOrderStatus);
        log.info("扫描到{}条未完成的子订单", orders.size());
        for (OrderDetail order : orders) {
            executor.execute(() -> checkTimeout(order));
        }
    }

    @Transactional(rollbackFor = Exception.class)
    void checkTimeout(OrderMaster order) {
        Date now = new Date();
        // 待接单状态的超时逻辑
        if (ZERO.equals(order.getOrderStatus())) {
            Date createTime = order.getCreateTime();
            Date overTime30min = getOverTime(createTime, 30 * 60 * 1000);
            Date overTime1h = getOverTime(createTime, 60 * 60 * 1000);
            // 是否已经超时
            boolean timeout = ONE.equals(order.getTimeout());
            if (!timeout) {
                if (overTime30min.before(now) && overTime1h.after(now)) {
                    // 30min未接单为超时
                    log.info("主订单[{}]超时30分钟", order.getId());
                    orderMasterService.updateTimeout(order.getId(), 1);
                    timeout = true;
                }
            }
            if (timeout) {
                if (overTime1h.before(now) && order.getWorkerId() != null) {
                    log.info("主订单[{}]超时60分钟", order.getId());
                    // 已超时 60min后取消超时状态 清空workerId
                    orderMasterService.updateTimeout(order.getId(), 0);
                    orderMasterService.removeWorker(order.getId());
                }
            }
            return;
        }

        // 未派单状态的超时逻辑
        if (ONE.equals(order.getOrderStatus())) {
            Date updateTime = order.getUpdateTime();
            Date overTime30min = getOverTime(updateTime, 30 * 60 * 1000);
            Date overTime4h = getOverTime(updateTime, 4 * 60 * 60 * 1000);
            Date overTime6h = getOverTime(updateTime, 6 * 60 * 60 * 1000);
            // 是否已经超时
            boolean timeout = ONE.equals(order.getTimeout());
            Integer fineTimes = order.getTimeoutFineTimes();
            if (!timeout) {
                if (overTime30min.before(now)) {
                    // 30min未接单为超时
                    log.info("主订单[{}]超时30分钟", order.getId());
                    orderMasterService.updateTimeout(order.getId(), 1);
                    timeout = true;
                }
            }

            if (timeout) {
                if (overTime4h.before(now) && ZERO.equals(fineTimes)) {
                    log.info("主订单[{}]超时4小时", order.getId());
                    orderMasterService.updateTimeout(order.getId(), 1, 1);
                    // insert 罚金记录
                    OrderTimeoutRecord record = new OrderTimeoutRecord(order.getId(), order.getWorkerId(), order.getDeptId(), order.getOrderStatus());
                    record.setPayMoney(getFineMoney(order));
                    record.setFineStatus(0);
                    orderFineRecordMapper.insert(record);
                    fineTimes = ONE;
                }

                if (overTime6h.before(now) && ONE.equals(fineTimes)) {
                    log.info("主订单[{}]超时6小时", order.getId());
                    orderMasterService.updateTimeout(order.getId(), 1, 2);
                    // insert 罚金记录
                    OrderTimeoutRecord record = new OrderTimeoutRecord(order.getId(), order.getWorkerId(), order.getDeptId(), order.getOrderStatus());
                    record.setPayMoney(getFineMoney(order));
                    record.setFineStatus(0);
                    orderFineRecordMapper.insert(record);
                }
            }
        }
    }

    /**
     * 判断是否超时
     *
     * @param order 订单信息
     */
    @Transactional(rollbackFor = Exception.class)
    void checkTimeout(OrderDetail order) {
        Date now = new Date();
        // 是否超时
        boolean timeout = ONE.equals(order.getTimeout());
        // 超时扣款次数
        Integer times = order.getTimeoutFineTimes();
        if (!timeout) {
            // 未超时的单
            if (order.getOrderStatus().equals(OrderStatus.SERVER.code())) {
                // 服务中状态要按预计上门时间计算4h超时
                Date overTime = getOverTime(order.getExpectTimeStart(), 4 * 60 * 60 * 1000);
                if (overTime.before(now)) {
                    log.info("订单[{}]服务中状态超时4小时 扣款", order.getId());
                    OrderTimeoutRecord record = new OrderTimeoutRecord(order.getId(), order.getWorkerId(), order.getDeptId(), order.getOrderStatus());
                    record.setPayMoney(getFineMoney(order));
                    record.setFineStatus(0);
                    orderFineRecordMapper.insert(record);
                    orderDetailService.updateTimeout(order.getId(), 1, 1);
                }
            } else if (timeoutOrderStatus.contains(order.getOrderStatus())) {
                // 其它状态用update_time判断30min超时
                Date overTime = getOverTime(order.getUpdateTime(), 30 * 60 * 1000);
                if (overTime.before(now)) {
                    log.info("订单[{}]超时30分钟", order.getId());
                    orderDetailService.updateTimeout(order.getId(), 1, 0);
                }
            }
            return;
        }

        if (times > 1) {
            // 已经扣过2次款了 不再扣款
            log.info("订单[{}]已经扣过2次超时款 不再扣款", order.getId());
        } else if (times == 0) {
            // 没扣过款的
            if (order.getOrderStatus().equals(OrderStatus.SERVER.code())) {
                // 服务中的订单第一次扣款在上面已经扣过了
                return;
            }
            Date overTime = getOverTime(order.getUpdateTime(), 4 * 60 * 60 * 1000);
            if (overTime.before(now)) {
                log.info("订单[{}]超时4h 扣款", order.getId());
                OrderTimeoutRecord record = new OrderTimeoutRecord(order.getId(), order.getWorkerId(), order.getDeptId(), order.getOrderStatus());
                record.setPayMoney(getFineMoney(order));
                record.setFineStatus(0);
                orderFineRecordMapper.insert(record);
                orderDetailService.updateTimeout(order.getId(), 1, 1);
            }
        } else if (times == 1) {
            // 扣过一次款的
            // 服务中状态取预计上门时间 其它状态取update_time
            Date orderTime = order.getOrderStatus().equals(OrderStatus.SERVER.code()) ? order.getExpectTimeStart() : order.getUpdateTime();
            Date overTime = getOverTime(orderTime, 6 * 60 * 60 * 1000);
            if (overTime.before(now)) {
                log.info("订单[{}]超时6h 再次扣款", order.getId());
                OrderTimeoutRecord record = new OrderTimeoutRecord(order.getId(), order.getWorkerId(), order.getDeptId(), order.getOrderStatus());
                record.setPayMoney(getFineMoney(order));
                record.setFineStatus(0);
                orderFineRecordMapper.insert(record);
                orderDetailService.updateTimeout(order.getId(), 1, 2);
            }
        }
    }

    /**
     * 计算订单罚金(固定罚金+比例罚金)
     */
    private BigDecimal getFineMoney(OrderDetail order) {
        OrderMaster orderMaster = orderMasterService.selectById(order.getOrderMasterId());
        FinancialDetail orderFinancial = financialDetailService.selectByOrderDetailId(order.getId());
        SysDeptConfig deptConfig = sysDeptConfigService.selectByDeptId(orderMaster.getDeptId());
        BigDecimal fineMoney = deptConfig.getGoingOutTime();
        // 如果扣款额为null或<0
        if (fineMoney == null || BigDecimal.ZERO.compareTo(fineMoney) > -1) {
            fineMoney = BigDecimal.ZERO;
        }
        BigDecimal timeoutRate = deptConfig.getGoingOutTimeRate();
        // 如果扣款比例 为null 或 <0 或 >1.00
        if (timeoutRate == null || BigDecimal.ZERO.compareTo(timeoutRate) > 0 || BigDecimal.ONE.compareTo(timeoutRate) < 0) {
            return fineMoney;
        }
        BigDecimal rateMoney = orderFinancial.getPayMoney().multiply(timeoutRate);
        return fineMoney.add(rateMoney);
    }

    /**
     * 计算订单罚金(固定罚金+比例罚金)
     */
    private BigDecimal getFineMoney(OrderMaster orderMaster) {
        FinancialMaster financialMaster = financialMasterService.selectByOrderMasterId(orderMaster.getId());
        SysDeptConfig deptConfig = sysDeptConfigService.selectByDeptId(orderMaster.getDeptId());
        BigDecimal fineMoney = deptConfig.getGoingOutTime();
        // 如果扣款额为null或<0
        if (fineMoney == null || BigDecimal.ZERO.compareTo(fineMoney) > -1) {
            fineMoney = BigDecimal.ZERO;
        }
        BigDecimal timeoutRate = deptConfig.getGoingOutTimeRate();
        // 如果扣款比例 为null 或 <0 或 >1.00
        if (timeoutRate == null || BigDecimal.ZERO.compareTo(timeoutRate) > 0 || BigDecimal.ONE.compareTo(timeoutRate) < 0) {
            return fineMoney;
        }
        BigDecimal rateMoney = financialMaster.getPayMoney().multiply(timeoutRate);
        return fineMoney.add(rateMoney);
    }

    /**
     * 计算超时时间
     *
     * @param orderTime 开始时间
     * @param time      超时时间
     * @return 超时时间
     */
    private Date getOverTime(Date orderTime, int time) {
        Date date = DateUtils.addMilliseconds(orderTime, time);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int hour = calendar.get(Calendar.HOUR_OF_DAY);
        if (hour < 8 || hour > 18) {
            // 超过19点的单，需要加上13个小时
            return DateUtils.addHours(date, 13);
        } else {
            return date;
        }
    }

    /**
     * @param orderTime 单据时间/可能为上门开始时间
     * @param time      超时时间，0.5h/4h/8h等
     * @return 最低限制时间
     * @throws Exception
     */
    private long getOverTimeSec(Date orderTime, long time) throws Exception {
        long overTime = orderTime.getTime();
        // 隔夜需要加上13个小时
        long isNight = 13 * 60 * 60 * 1000;
        //设置日期格式
        SimpleDateFormat df = new SimpleDateFormat("HH:mm");
        Date nowTime = df.parse(df.format(new Date()));
        // 早上8点-晚上19点
        Date amBeginTime = df.parse("08:00");
        Date pmEndTime = df.parse("19:00");
        //设置当前时间
        Calendar date = Calendar.getInstance();
        date.setTime(nowTime);
        //设置开始时间
        Calendar beginTime = Calendar.getInstance();
        beginTime.setTime(amBeginTime);
        //设置结束时间
        Calendar endTime = Calendar.getInstance();
        endTime.setTime(pmEndTime);
        // 符合时间区间
        if (date.after(beginTime) && date.before(endTime)) {
            // 当日单
            if (checkIsTodayOrder(orderTime)) {
                overTime = overTime + time;
            } else {
                overTime = overTime + isNight + time;
            }
        }
        return overTime;
    }

    private Boolean checkIsTodayOrder(Date orderTime) throws Exception {
        // 订单日期
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        Date orderDate = df.parse(df.format(orderTime));
        // 当前日期
        Date now = df.parse(df.format(new Date()));
        if (orderDate.before(now)) {
            return false;
        } else {
            return true;
        }
    }


    @Override
    public void autoFinishOrder() {
        // 子订单自动完单
        // 查询出"待确认"状态的子订单
        List<OrderDetail> orderDetails = orderDetailService.selectByStatus(Collections.singletonList(OrderStatus.FINISH_CHECK.code()));
        long now = System.currentTimeMillis();
        long day14ago = now - (60 * 60 * 1000L);
//        long day14ago = now - 10000L;
        for (OrderDetail orderDetail : orderDetails) {
            // 筛选符合自动确认的订单
            if (day14ago > orderDetail.getWorkFinishTime().getTime()) {
                log.info("子订单自动完成[id={}, code={}]", orderDetail.getId(), orderDetail.getCode());
                try {
                    // 子订单完单流程(分账与提现)
                    orderDetailService.finish(orderDetail.getId());
                } catch (Exception e) {
                    log.error("子订单自动完成[id={}, code={}]出错", orderDetail.getId(), orderDetail.getCode(), e);
                }
            }
        }

        // 主订单自动完单
        List<OrderMaster> orderMasters = orderMasterService.selectUnfinished();
        for (OrderMaster om : orderMasters) {
            try {
                boolean allAssign = orderMasterService.isAllAssign(om.getId());
                // 如果存在未派单的子订单 就不刷新主单状态
                if (!allAssign) {
                    continue;
                }
                List<OrderDetail> ods = orderDetailService.selectByOrderMasterId(om.getId());
                Set<Integer> statusSet = ods.stream().map(OrderDetail::getOrderStatus).collect(Collectors.toSet());
                // 没有子单,未派单的情况不刷新主单状态
                if (CollectionUtils.isEmpty(statusSet)) {
                    continue;
                }
                boolean allFinish = true;
                for (Integer integer : statusSet) {
                    if (integer < 5) {
                        allFinish = false;
                        break;
                    }
                }
                // 如果已经不存在"已完成"和"已取消"以外的子订单 就把主订单也改为完成
                if (allFinish) {
                    log.info("主订单自动完成[id={} code={}]", om.getId(), om.getCode());
                    orderMasterService.finish(om.getId());
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
    }

    @Override
    public void autoChangeDrawCashStatus() {
    }

}
