package com.wteam.framework.modules.book.service.impl;

import cn.hutool.core.util.StrUtil;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.sun.org.apache.bcel.internal.generic.NEW;
import com.wteam.framework.common.enums.OrderTypeEnums;
import com.wteam.framework.common.enums.ResultCode;
import com.wteam.framework.common.enums.ResultUtil;
import com.wteam.framework.common.exception.ServiceException;
import com.wteam.framework.common.security.AuthUser;
import com.wteam.framework.common.security.context.UserContext;
import com.wteam.framework.common.vo.ResultMessage;
import com.wteam.framework.modules.book.entity.OrderInfo;
import com.wteam.framework.modules.book.entity.Venue;
import com.wteam.framework.modules.book.entity.dto.OrderReq;
import com.wteam.framework.modules.book.mapper.OrderInfoMapper;
import com.wteam.framework.modules.book.mapper.VenueMapper;
import com.wteam.framework.modules.book.service.OrderInfoService;
import com.wteam.framework.modules.book.service.PaymentInfoService;
import com.wteam.framework.modules.pay.entity.vo.CallbackParamVO;
import com.wteam.framework.modules.pay.entity.vo.OrderStatusEnum;
import com.wteam.framework.modules.system.entity.dos.Setting;
import com.wteam.framework.modules.system.entity.dto.WechatPaymentSetting;
import com.wteam.framework.modules.system.entity.enums.SettingEnum;
import com.wteam.framework.modules.system.service.SettingService;
import com.wteam.framework.modules.user.entity.User;
import com.wteam.framework.modules.user.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.constraints.NotNull;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * (OrderInfo)表服务实现类
 *
 * @author doncic
 * @since 2023-09-20 13:12:50
 */
@Slf4j
@Service("orderInfoService")
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {


    @Autowired
    private UserMapper userMapper;
    @Autowired
    private OrderInfoService orderInfoService;
    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private SettingService settingService;
    @Autowired
    private VenueMapper venueMapper;
    @Autowired
    private PaymentInfoService paymentInfoService;
    @Autowired
    private RedisTemplate redisTemplate;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultMessage generateOrder(String accessToken, OrderReq orderReq) {
        // 检查参数是否有效
        if (accessToken == null || orderReq == null) {
            return ResultUtil.error(ResultCode.USER_AUTHORITY_ERROR);
        }
        // 获取用户ID
        Long userId = getUserIdFromAccessToken(accessToken);
        // 检查用户是否存在
        User user = userMapper.selectById(userId);
        if (user == null) {
            return ResultUtil.error(ResultCode.USER_NEED_LOGIN);
        }


        //要进行时间的校验
        LambdaQueryWrapper<OrderInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(OrderInfo::getOrderDate, orderReq.getOrderDate());
        List<OrderInfo> orderInfos = orderInfoMapper.selectList(lambdaQueryWrapper);
        boolean b = isOrderTimeValid(orderInfos, orderReq.getOrderSt(), orderReq.getOrderEd());

        if (b) {
            // 创建订单
            OrderInfo orderInfo = mapOrderRequestToOrderInfo(orderReq, String.valueOf(userId));
            Double orderPrice = orderInfo.getOrderPrice();
            Double reqOrderPrice = orderReq.getOrderPrice();
            if (orderPrice != reqOrderPrice) {
                return ResultUtil.error(ResultCode.PRICE_ERROR);
            }
            int insert = orderInfoMapper.insert(orderInfo);
            String id = orderInfo.getId();
            log.info("这里的订单id为：{}", id);
            if (insert > 0) {
                // 订单成功保存后，设置订单的过期时间为15分钟
                String key = "orderInfo:" + orderInfo.getId();
                redisTemplate.opsForValue().set(key, orderInfo, 15, TimeUnit.MINUTES);
                log.info("这里的订单id为：{}", orderInfo.getId());
                return ResultUtil.data(id);
            }
            return ResultUtil.error(ResultCode.ERROR);
        }
        return ResultUtil.error(ResultCode.ORDER_EXIST);
    }


    public boolean isOrderTimeValid(List<OrderInfo> orderInfos, Date newOrderStart, Date newOrderEnd) {
        for (OrderInfo existingOrder : orderInfos) {
            Date existingOrderStart = existingOrder.getOrderSt();
            Date existingOrderEnd = existingOrder.getOrderEd();

            if (newOrderStart.equals(existingOrderStart) && newOrderEnd.equals(existingOrderEnd)) {
                return false;
            }
        }
        return true; // 时间不重叠且不完全相同
    }


    public void checkAndRemoveExpiredOrders() {
        // 这里遍历所有订单，检查订单的过期时间，如果过期则删除
        Set<String> keys = redisTemplate.keys("orderInfo:*");
        if (keys != null) {
            for (String key : keys) {
                Long remainingTime = redisTemplate.getExpire(key);
                if (remainingTime != null && remainingTime <= 0) {
                    redisTemplate.delete(key);
                    // 在这里你可以执行其他处理，如发送订单过期通知
                }
            }
        }
    }

    @Override
    public Boolean checkOrder(Long id) {
        OrderInfo orderInfo = this.getById(id);
        if (null == orderInfo) {
            log.info("回调处理，支付订单号{}不存在", id);
            return false;
        }
        return OrderStatusEnum.PAID.name().equals(orderInfo.getOrderState()) ? Boolean.FALSE : Boolean.TRUE;
    }

    @Override
    public void processOrders(CallbackParamVO callbackParamVO) {
        OrderInfo orderInfo = this.getById(callbackParamVO.getSn());
        if (null == orderInfo) {
            log.info("回调处理，支付订单号{}不存在", callbackParamVO.getSn());
            throw new ServiceException(ResultCode.ORDER_NOT_EXIST);
        }
        // 更新订单转态
        this.update(new LambdaUpdateWrapper<OrderInfo>().eq(OrderInfo::getId, callbackParamVO.getSn()).set(OrderInfo::getOrderState, OrderStatusEnum.PAID).set(OrderInfo::getCreateTime, callbackParamVO.getSuccessTime()).set(OrderInfo::getTransactionId, callbackParamVO.getTransactionId()));
    }


    @Override
    public ResultMessage bookStatus(@NotNull Long id, Date dateTime) {
        // 将传入的日期（dateTime）转换为年月日格式的字符串
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String targetDate = dateFormat.format(dateTime);
        log.info("此时的时间为：{}", targetDate);
        // 使用 LambdaQueryWrapper 构造查询条件
        LambdaQueryWrapper<OrderInfo> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(OrderInfo::getStoreId, id).eq(OrderInfo::getOrderDate, targetDate).eq(OrderInfo::getOrderType, OrderTypeEnums.RENTAL);
        List<OrderInfo> orderInfos = orderInfoMapper.selectList(wrapper);
        log.info("对应的订单信息为：{}", orderInfos);
        List<OrderInfo> collect = orderInfos.stream()
                .filter(orderInfo -> orderInfo.getOrderState() != null)
                .collect(Collectors.toList());
        log.info("此时过滤后对应的订单信息为：{}", collect);
        /**
         * 这里订场情况拆线呢分为
         * 1-->根据该场地id没有查到关联id,就把当天的订场情况全部返回
         * 2-->根据该场地id查到关联id
         *   1-->此时的关联id只有一个,那此时这个场地即为篮球半场,那次此时的对应的关联id为篮球全场,那同一时间段的篮球全场就无法进行预订
         *   2-->此时的关联id为两个,那此时的这个场地即为篮球全场,那次的关联id为两个篮球半场,那同一时间段的另外两个篮球半场就无法进行预订
         * 返回给前端要禁用的场地
         */
        List<OrderInfo> orderInfoList = new ArrayList<>();
        for (OrderInfo order : collect) {
            //获取场地id
            Long venueId = order.getVenueId();
            log.info("对应的场地id为：{}", venueId);
            //获取场地信息
            Venue venue = venueMapper.selectById(venueId);
            log.info("对应的场地为：{}", venue);
            //得到该场地是否有关联id
            String relevancyId = venue.getRelevancyId();
            log.info("对应的场地相关id为：{}", relevancyId);
            if ("0".equals(relevancyId)) {
                // 1. 处理场地没有关联的情况，返回当天的订场情况
                orderInfoList.add(order);
            } else {
                // 2. 处理场地有关联的情况，需要进一步判断
                String[] relevantIds = relevancyId.split(","); // 假设关联 id 以逗号分隔
                if (relevantIds.length == 1) {
                    // 2.1 处理关联 id 只有一个的情况，即半场
                    // 那此时同时间段的全场不允许进行预订
                    String newVariable0 = relevantIds[0]; // 将第一个 id 赋给新变量
                    log.info("对应的场地id为：{}", newVariable0);
                    String cleanedId = newVariable0.replaceAll("\\[|\\]|\"", "");
                    log.info("此时优化之后的id为:{}", cleanedId);
                    //构建订单信息
                    OrderInfo orderInfo1 = new OrderInfo();
                    orderInfo1.setVenueId(Long.valueOf(cleanedId));
                    orderInfo1.setOrderSt(order.getOrderSt());
                    orderInfo1.setOrderEd(order.getOrderEd());
                    log.info("对应的订单信息1为：{}", orderInfo1);
                    OrderInfo orderInfo2 = new OrderInfo();
                    orderInfo2.setVenueId(venueId);
                    orderInfo2.setOrderSt(order.getOrderSt());
                    orderInfo2.setOrderEd(order.getOrderEd());
                    log.info("对应的订单信息2为：{}", orderInfo2);
                    orderInfoList.add(orderInfo1);
                    orderInfoList.add(orderInfo2);
                } else {
                    // 2.2 处理关联 id 多个的情况，即全场
                    String newVariable0 = relevantIds[0];
                    String cleanedId1 = newVariable0.replaceAll("\\[|\\]|\"", "");
                    log.info("此时的cleanedId1:{}", cleanedId1);
                    String newVariable1 = relevantIds[1];
                    String cleanedId2 = newVariable1.replaceAll("\\[|\\]|\"", "");
                    log.info("此时的cleanedId2:{}", cleanedId2);
                    //构建订单信息
                    OrderInfo orderInfo1 = new OrderInfo();
                    orderInfo1.setVenueId(Long.valueOf(cleanedId1));
                    orderInfo1.setOrderSt(order.getOrderSt());
                    orderInfo1.setOrderEd(order.getOrderEd());
                    log.info("对应的订单信息1为：{}", orderInfo1);
                    OrderInfo orderInfo2 = new OrderInfo();
                    orderInfo2.setVenueId(Long.valueOf(cleanedId2));
                    orderInfo2.setOrderSt(order.getOrderSt());
                    orderInfo2.setOrderEd(order.getOrderEd());
                    log.info("对应的订单信息2为：{}", orderInfo2);
                    OrderInfo orderInfo3 = new OrderInfo();
                    orderInfo3.setVenueId(venueId);
                    orderInfo3.setOrderSt(order.getOrderSt());
                    orderInfo3.setOrderEd(order.getOrderEd());
                    log.info("对应的订单信息3为：{}", orderInfo3);
                    orderInfoList.add(orderInfo1);
                    orderInfoList.add(orderInfo2);
                    orderInfoList.add(orderInfo3);
                }
            }
        }
        Map<String, List<Map<String, Object>>> stringListMap = formatOrderInfo(orderInfoList, targetDate);
        log.info("此时返回订场情况为:{}", stringListMap);
        return ResultUtil.data(stringListMap);
    }


    public Map<String, List<Map<String, Object>>> formatOrderInfo(List<OrderInfo> orderInfos, String targetDate) {
        Map<String, List<Map<String, Object>>> result = new HashMap<>();
        List<Map<String, Object>> dataList = new ArrayList<>();

        for (OrderInfo orderInfo : orderInfos) {
            Map<String, Object> orderMap = new HashMap<>();
            orderMap.put("venueId", orderInfo.getVenueId());
            orderMap.put("orderSt", formatTime(orderInfo.getOrderSt()));
            orderMap.put("orderEd", formatTime(orderInfo.getOrderEd()));
            dataList.add(orderMap);
        }

        result.put(targetDate, dataList);
        return result;
    }

    private String formatTime(Date time) {
        SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
        return timeFormat.format(time);
    }


    /**
     * 数组格式化方法
     *
     * @param data
     * @return
     */
    private String formatJson(List<Map<String, String>> data) {
        StringBuilder result = new StringBuilder();
        result.append("[\n");

        for (int i = 0; i < data.size(); i++) {
            Map<String, String> item = data.get(i);
            result.append("  {\n");
            int j = 0;
            for (Map.Entry<String, String> entry : item.entrySet()) {
                result.append("    \"").append(entry.getKey()).append("\" : \"").append(entry.getValue()).append("\"");
                if (j < item.size() - 1) {
                    result.append(",");
                }
                result.append("\n");
                j++;
            }
            result.append("  }");
            if (i < data.size() - 1) {
                result.append(",");
            }
            result.append("\n");
        }

        result.append("]\n");
        return result.toString();
    }


    public static WechatPaymentSetting getWechatPaymentSetting(SettingService settingService) {
        Setting setting = settingService.get(SettingEnum.WECHAT_PAYMENT.name());
        if (StrUtil.isBlank(setting.getSettingValue())) {
            throw new ServiceException(ResultCode.WECHAT_PAYMENT_NOT_SETTING);
        }
        return new Gson().fromJson(setting.getSettingValue(), WechatPaymentSetting.class);
    }


    private Long getUserIdFromAccessToken(String accessToken) {
        AuthUser authUser = UserContext.getAuthUser(accessToken);
        return Long.valueOf(authUser.getId());
    }


    private OrderInfo mapOrderRequestToOrderInfo(OrderReq orderReq, String userId) {
        User user = userMapper.selectById(userId);
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setUserId(userId);
        orderInfo.setStoreId(orderReq.getStoreId());
        orderInfo.setCreateTime(new Date());
        orderInfo.setCreateBy(user.getNickName());
        orderInfo.setVenueId(orderReq.getVenueId());
        orderInfo.setOrderDate(orderReq.getOrderDate());
        orderInfo.setOrderSt(orderReq.getOrderSt());
        log.info("此时的订场时间为：{}", orderReq.getOrderSt());
        orderInfo.setOrderEd(orderReq.getOrderEd());
        orderInfo.setOrderType(orderReq.getOrderType());
        orderInfo.setPhoneNumber(orderReq.getPhoneNumber());
        orderInfo.setOrderPrice(orderReq.getOrderPrice());
        return orderInfo;
    }

    // 在这里添加订单状态的验证逻辑，例如检查订单时间是否有效等
// 如果订单有效返回true，否则返回false
    private boolean isOrderValid(OrderReq orderReq) {
        return false;
    }
}
