package com.wteam.controller.hardware;

/**
 * @author doncic
 * @date 2023/9/27 19:13
 */

import cn.hutool.core.util.ObjectUtil;
import com.wteam.framework.common.enums.*;
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.Card;
import com.wteam.framework.modules.book.entity.OrderInfo;
import com.wteam.framework.modules.book.entity.reqp.hardwareReq;
import com.wteam.framework.modules.book.entity.vo.TimeCodeVo;
import com.wteam.framework.modules.book.mapper.CardMapper;
import com.wteam.framework.modules.book.mapper.OrderInfoMapper;
import com.wteam.framework.modules.book.service.OrderInfoService;
import com.wteam.framework.modules.hardware.ApiQrCodeUtil;
import com.wteam.framework.modules.user.entity.User;
import com.wteam.framework.modules.user.mapper.UserMapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.Temporal;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@Tag(name = "硬件相关接口管理")
@RestController
@RequestMapping("/v1/hardware")
public class HardwareController {

    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private OrderInfoService orderInfoService;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private CardMapper cardMapper;

    /**
     * 这里理一下思路
     * 这里是反扫码设置，先前已经使用hutool接口进行第三方的url回调设置了
     * 根据传入的信息解析可以获得  扫码的时间、二维码信息、devmac指的是生命周期
     * 这里根据二维码信息可以获得对应id
     * 如果是订场订单生成的code ---》userId和orderId
     * 如果是计时订单生成的code ---》userId和orderId
     * 如果是月卡或者次卡生成的code ---》userId和有效天数
     * 根据orderId获取到对应的订单信息
     * 如果是计时订单
     * 先将时间存入starttime
     * 第二次进行时间校验 -》第二次的时间必须要是
     * 然后进行业务处理
     */
    @Operation(summary = "反扫码设备第三方二维码核销说明")
    @PostMapping("/verification")
    public ResultMessage hardware(@RequestBody hardwareReq hardwareReq) throws ParseException {
        //获取请求体中的具体数据
        String qcode = hardwareReq.getQcode();
        String time = hardwareReq.getTime();
        log.info("此时扫码的时间为：{}", time);
        String devmac = hardwareReq.getDevmac();
        log.info("此时获取的二维码为{}", qcode);
        // 定义正则表达式来匹配数字
        Pattern pattern = Pattern.compile("\\d+");
        Matcher matcher = pattern.matcher(qcode);
        //解析qcode的值
        String date = null;
        String userId = null;
        String orderId = null;
        // 查找并存储匹配的数字
        int count = 0;
        while (matcher.find() && count < 3) {
            String number = matcher.group();
            if (count == 0) {
                date = number;
            } else if (count == 1) {
                userId = number;
            } else if (count == 2) {
                orderId = number;
            }
            count++;
        }
        log.info("此时获取出来的userId为{}", userId);
        log.info("此时获取出来的orderId为{}", orderId);
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        log.info("此时的订单信息为{}", orderInfo);
        if (orderInfo == null) {
            return ResultUtil.error(ResultCode.ENTITY_NULL);
        }
        //这里先判断是什么订单
        String orderType = orderInfo.getOrderType();

        //根据订场类型不同实现不同的扫码逻辑
        switch (orderType) {
            case "RENTAL":
                // 处理租场订单类型的二维码注销逻辑
                return RentalOrder(orderId, time);
            case "TICKET":
                // 处理门票订单类型的二维码注销逻辑
                return TicketOrder(orderId, time);
            case "TIMER":
                // 处理计时订单类型的二维码注销逻辑
                return TimerOrder(orderId, time);
            case "MONTHLY":
                // 处理月卡订单类型的二维码注销逻辑
                return MonthlyOrder(orderId, time);
            default:
                // 处理未知订单类型的情况
                break;
        }
        return null;
    }

    /**
     * 门票的扫码逻辑
     * 只要数据库存在这个二维码即可
     * 在二维码注册的时候就已经限制的门票只能核销两次
     *
     * @param orderId
     * @return
     */
    private ResultMessage TicketOrder(String orderId, String time) throws ParseException {
        //获取订单信息
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        //处理时间格式
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        Date currentTime = dateFormat.parse(time);
        //处理业务代码
        //先处理订场订单的情况
        if (orderTypeEnum.TICKET.toString().equals(orderInfo.getOrderType())) {
            if (orderInfo.getStartTime() == null) {
                // 第一次调用接口，设置startTime
                orderInfo.setStartTime(currentTime);
                orderInfo.setOrderState(String.valueOf(OrderStatusEnum.IN_USE));
                orderInfoMapper.updateById(orderInfo);
                String qrCode = orderInfo.getQrCode();
                if (ObjectUtil.isNull(qrCode)) {
                    return ResultUtil.error(ResultCode.QRCODE_ERROR);
                }
            } else {
                if (orderInfo.getEndTime() == null) {
                    // 第二次调用接口，设置endTime，并计算费用
                    orderInfo.setEndTime(currentTime);
                    orderInfo.setOrderState(String.valueOf(OrderStatusEnum.USED));
                    orderInfoMapper.updateById(orderInfo);
                    return ResultUtil.success(ResultCode.QRCODE);
                }
            }
        }
        return ResultUtil.error(ResultCode.QRCODE_ERROR);
    }

    /**
     * 月卡的核销业务逻辑处理
     * 月卡的二维码注册的时候有效期直到月卡失效
     * 先检测二维码是否存在
     * 再判断此时二维码是否失效
     * 只要未失效
     * 不限时间不限次数
     *
     * @param orderId
     * @param time
     * @return
     */
    private ResultMessage MonthlyOrder(String orderId, String time) throws ParseException {
        //获取order信息
        //获取订单信息
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        //处理业务代码
        String qrCode = orderInfo.getQrCode();
        //获得卡信息
        Integer cardId = orderInfo.getCardId();
        Card card = cardMapper.selectById(cardId);
        String endDate = card.getEndDate();
        // 假设时间格式为 "yyyy-MM-dd HH:mm:ss"
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date timeDate = sdf.parse(time);
        Date endDateDate = sdf.parse(endDate);
        //处理扫码业务
        if (timeDate.before(endDateDate)) {
            if (ObjectUtil.isNotNull(qrCode)) {
                return ResultUtil.success(ResultCode.QRCODE);
            }
        }
        // time 在 endDate 之后或者相等
        return ResultUtil.error(ResultCode.QRCODE_ERROR);
    }


    /**
     * 计时卡逻辑
     * 根据第一次传入的时间设置为用户进场时间
     * 根据第一次进场时间判断时间段，根据时间段的不同，设置订单的价格不同
     * 根据第二次传入的时间设置为用户离场时间
     * 根据第一次和第二次的差值计算价格
     */
    @SneakyThrows
    private ResultMessage TimerOrder(String orderId, String time) {
        //获取订单信息
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        //处理时间格式
        //处理时间格式
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
        Date date = sdf.parse(time);
        // 设置不同时间段的价格
        Date startTime1 = sdf.parse("09:30");
        Date endTime1 = sdf.parse("18:00");
        Date startTime2 = sdf.parse("18:30");

        //先处理订场订单的情况
        if (orderInfo.getStartTime() == null) {
            // 第一次调用接口，设置startTime
            orderInfo.setStartTime(date);
            orderInfo.setOrderState(String.valueOf(OrderStatusEnum.IN_USE));
            log.info("此时的订单信息为:{}", orderInfo);
            orderInfoMapper.updateById(orderInfo);
            if (date.after(startTime1) && date.before(endTime1)) {
                // 当前时间在 09:30 - 18:00 之间，价格为 8 元/小时
                double initialPrice = 8.0;
                orderInfo.setOrderPrice(initialPrice);
                orderInfo.setOrderState(String.valueOf(OrderStatusEnum.WAITING_TO_PAY));
                orderInfoService.updateById(orderInfo);
                return ResultUtil.success(ResultCode.QRCODE);
            } else if (date.after(startTime2)) {
                // 当前时间在 18:30 之后，价格为 10 元/小时
                double initialPrice = 10.0;
                orderInfo.setOrderPrice(initialPrice);
                orderInfo.setOrderState(String.valueOf(OrderStatusEnum.WAITING_TO_PAY));
                orderInfoService.updateById(orderInfo);
                return ResultUtil.success(ResultCode.QRCODE);
            }
        } else {
            if (orderInfo.getEndTime() == null) {
                // 第二次调用接口，设置endTime，并计算费用
                orderInfo.setEndTime(date);
                // 计算时间差（以分钟为单位）
                long timeDifferenceMillis = orderInfo.getEndTime().getTime() - orderInfo.getStartTime().getTime();
                long minutesDifference = TimeUnit.MILLISECONDS.toMinutes(timeDifferenceMillis);
                // 计算超出一分钟的时间
                long extraMinutes = Math.max(0, minutesDifference - 1);
                // 根据超出的分钟计算费用
                double pricePerMinute = 8.0 / 60.0; // 8元/60分钟
                double totalPrice = pricePerMinute * extraMinutes;
                orderInfo.setOverPrice(totalPrice);
                orderInfo.setOrderState(String.valueOf(OrderStatusEnum.WAITING_SUPPLEMENTS));
                orderInfoService.updateById(orderInfo);
            }
            return ResultUtil.success(ResultCode.QRCODE);
        }
        return ResultUtil.success(ResultCode.QRCODE);
    }


    /**
     * 租场订单实现逻辑
     * 先获取第一次时间设置为用户进场时间 第二次时间先判断是否在订场时间段之内 如果在就直接放行
     * 超过订场时间段，则计算超出订场时间、
     *
     * @param orderId
     * @return
     */
    private ResultMessage RentalOrder(String orderId, String time) throws ParseException {
        //获取订单信息
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        //处理时间格式
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        Date currentTime = dateFormat.parse(time);
        //先处理订场订单的情况
        if (orderTypeEnum.RENTAL.toString().equals(orderInfo.getOrderType())) {
            if (orderInfo.getStartTime() == null) {
                // 第一次调用接口，设置startTime
                orderInfo.setStartTime(currentTime);
                orderInfo.setOrderState(String.valueOf(OrderStatusEnum.IN_USE));
                orderInfoMapper.updateById(orderInfo);
                return ResultUtil.data(ResultCode.QRCODE);
            } else {
                if (orderInfo.getEndTime() == null) {
                    // 第二次调用接口，设置endTime，并计算费用
                    orderInfo.setEndTime(currentTime);
                    orderInfoMapper.updateById(orderInfo);
                    // 校验当前时间是否在ordered时间之前
                    if (currentTime.before(orderInfo.getOrderEd())) {
                        // 在ordered时间之前，返回状态码200
                        orderInfo.setOrderState(String.valueOf(OrderStatusEnum.USED));
                        orderInfoMapper.updateById(orderInfo);
                        return ResultUtil.data(ResultCode.QRCODE);
                    } else {
                        // 超过ordered时间，计算超过的分钟数
                        long minutesDifference = calculateMinutesDifference(orderInfo.getOrderEd(), currentTime);
                        //计算超时需要付钱金额
                        double v = calculateAmount(minutesDifference);
                        //获取订单支付金额
                        Double orderPrice = orderInfo.getOrderPrice();
                        //需要支付的金额
                        double v1 = v * orderPrice;
                        orderInfo.setOverPrice(v1);
                        orderInfoService.updateById(orderInfo);
                    }
                }
            }
        }
        return ResultUtil.error(ResultCode.QRCODE_ERROR);
    }

    // 计算分钟差
    private long calculateMinutesDifference(Date startTime, Date endTime) {
        Duration duration = Duration.between((Temporal) startTime, (Temporal) endTime);
        return duration.toMinutes();
    }

    // 定义一个方法来根据时间差计算费用
    private double calculateAmount(long timeDifferenceMinutes) {
        // 实现计费计算逻辑
        // 根据时间差计算费用
        double billingAmount = 0.0;
        if (timeDifferenceMinutes >= 45) {
            billingAmount = 0.75; // 按小时费率的3/4
        } else if (timeDifferenceMinutes >= 30) {
            billingAmount = 0.5; // 按小时费率的1/2
        } else if (timeDifferenceMinutes >= 15) {
            billingAmount = 0.25; // 按小时费率的1/4
        }
        return billingAmount;
    }

    //        // 查询是否存在相同的二维码订单信息
//        LambdaQueryWrapper<OrderInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
//        lambdaQueryWrapper.eq(OrderInfo::getQrCode, qcode);
//        List<OrderInfo> orderInfos = orderInfoMapper.selectList(lambdaQueryWrapper);
//        boolean empty = orderInfos.isEmpty();
//        if (empty) {
//            orderInfo.setOrderState(String.valueOf(OrderStatusEnum.IN_USE));
//            orderInfoService.save(orderInfo);
//            return ResultUtil.success(ResultCode.QRCODE);
//        }
//        return ResultUtil.error(ResultCode.QRCODE_ERROR);


    /**
     * 计时卡实现思路
     * 传入token校验解析 获得userId
     * 查出昵称
     * 生成二维码-》计时码注册到硬件只能使用两次 -》调用硬件接口注册-》处理响应数据-》成功-》返回-》 二维码包含userID和手机号信息
     * 如果二维码注册成功，就生成计时订单
     * 用户拿着计时码去扫码进场
     * 一扫码就先支付一个小时的价钱
     * 然后出来的时候也获得一个时间
     * 根据时间比对
     * 如果小于 就直接开闸离开
     * 如果大于一个小时就继续进行扣费
     *
     * @param accessToken
     * @return
     */
    @Operation(summary = "计时卡")
    @PostMapping("/timeCard/{accessToken}")
    public ResultMessage timeCard(@PathVariable("accessToken") String accessToken) {
        //解析校验token获得用户id
        AuthUser authUser = UserContext.getAuthUser(accessToken);
        assert authUser != null;
        String userId = authUser.getId();
        log.info("此时的用户id为:{}", userId);
        //根据userId查询user信息
        User user = userMapper.selectById(userId);
        // 处理nickName为null的情况
        String nickName = (user.getNickName() != null) ? user.getNickName() : "";
        // 获取当前日期
        LocalDate currentDate = LocalDate.now();
        // 格式化日期为字符串
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        String formattedDate = currentDate.format(formatter);
        /**
         * 这里存储计时订单信息
         */
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setUserId(userId);
        orderInfo.setCreateTime(new Date());
        orderInfo.setStoreId(9376L);
        orderInfo.setOrderType(String.valueOf(orderTypeEnum.TIMER));
        orderInfo.setOrderPrice((double) 100);
        orderInfoService.save(orderInfo);

        String data = "pxo_" + formattedDate + "_" + userId + "_" + orderInfo.getId() + "_00";
        Boolean flag = ApiQrCodeUtil.callApiWithUser(data);

        if (flag) {
            orderInfo.setQrCode(data);
            orderInfoService.updateById(orderInfo);
            //判断响应结果
            TimeCodeVo timeCodeVo = new TimeCodeVo();
            timeCodeVo.setCode(data);
            timeCodeVo.setNickName(nickName);
            return ResultUtil.data(timeCodeVo);
        }
        return ResultUtil.error(ResultCode.TIME_CODE_ERROR);
    }
}
