package cn.iocoder.yudao.module.member.service.orderspacecapsule;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.member.controller.admin.orderspacecapsule.vo.*;
import cn.iocoder.yudao.module.member.dal.dataobject.orderspacecapsule.OrderSpaceCapsuleDO;
import cn.iocoder.yudao.module.member.dal.dataobject.spacecapsule.SpaceCapsuleDO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.dal.mysql.orderspacecapsule.OrderSpaceCapsuleMapper;
import cn.iocoder.yudao.module.member.enums.*;
import cn.iocoder.yudao.module.member.service.amount.DeductionService;
import cn.iocoder.yudao.module.member.service.spacecapsule.SpaceCapsuleService;
import cn.iocoder.yudao.module.member.service.statisticsspacecapsuleorder.StatisticsSpaceCapsuleOrderService;
import cn.iocoder.yudao.module.member.service.user.MemberUserService;
import cn.iocoder.yudao.module.system.api.carteen.CarteenApi;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.imageio.ImageIO;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*;

/**
 * 太空舱订单 Service 实现类
 *
 * @author 管理员
 */
@Service
@Validated
public class OrderSpaceCapsuleServiceImpl implements OrderSpaceCapsuleService {

    @Resource
    private OrderSpaceCapsuleMapper orderSpaceCapsuleMapper;
    @Resource
    private  StatisticsSpaceCapsuleOrderService statisticsSpaceCapsuleOrderService;
    @Resource
    private DeductionService deductionService;
    @Resource
    private SpaceCapsuleService spaceCapsuleService;
    @Resource
    private MemberUserService userService;
    @Resource
    private CarteenApi carteenApi;
    private static final String URL="https://gateway.biandianxia.com/encrypt/sharedevice";
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createOrderSpaceCapsule(OrderSpaceCapsuleSaveReqVO createReqVO) {
        // 插入对象转换
        OrderSpaceCapsuleDO orderSpaceCapsule = BeanUtils.toBean(createReqVO, OrderSpaceCapsuleDO.class);

        // 校验状态是否为未使用
        if (!SpaceCapsuleOrderEnum.SPACE_CAPSULE_ORDER_ENUM_UNUSED.getCode().equals(orderSpaceCapsule.getStatus())) {
            throw exception(ORDER_SPACE_CAPSULE_ERREO);
        }
        // 获取用户信息及余额
        MemberUserDO user = userService.getUser(orderSpaceCapsule.getUserId());
        BigDecimal initialMoney = user.getMoney();
        // 设置变动前的余额
        orderSpaceCapsule.setStartMoney(initialMoney);
        orderSpaceCapsule.setPhone(user.getMobile());
        //获取订单总金额
        BigDecimal multiply = orderSpaceCapsule.getComboPrice().multiply(BigDecimal.valueOf(orderSpaceCapsule.getComboNum()));
        orderSpaceCapsule.setMoney(multiply);
        // 扣除余额
        deductionService.spaceDeduct(orderSpaceCapsule.getUserId(), orderSpaceCapsule.getMoney(), CostTypeEnum.SPACE.getCode(),createReqVO.getCarteenId());
        // 设置变动后的余额
        orderSpaceCapsule.setEndMoney(initialMoney.subtract(orderSpaceCapsule.getMoney()));
        // 设置支付方式
        orderSpaceCapsule.setPayMethods(PayMethodsEnum.WX_LITE.getName());
        //设置门店名称
        String storesName = carteenApi.getCarteenById(orderSpaceCapsule.getCarteenId()).getStoresName();
        orderSpaceCapsule.setCarteenName(storesName);
        // 插入订单数据
        orderSpaceCapsuleMapper.insert(orderSpaceCapsule);
        // 返回订单 ID
        return orderSpaceCapsule.getId();
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateOrderSpaceCapsule(OrderSpaceCapsuleSaveReqVO updateReqVO) {
        // 校验存在
        validateOrderSpaceCapsuleExists(updateReqVO.getId());
        // 更新
        OrderSpaceCapsuleDO updateObj = BeanUtils.toBean(updateReqVO, OrderSpaceCapsuleDO.class);
        // 校验状态是否为不可用
        if (updateObj.getStatus().equals(SpaceCapsuleOrderEnum.SPACE_CAPSULE_ORDER_ENUM_UNUSED.getCode())) {
            throw exception(ORDER_SPACE_CAPSULE_ERREO);
        }
        // 判断是否需要更新状态
        OrderSpaceCapsuleDO orderSpaceCapsuleDO = orderSpaceCapsuleMapper.selectById(updateObj.getId());
        updateObj.setCarteenId(orderSpaceCapsuleDO.getCarteenId());
        Integer currentStatus = orderSpaceCapsuleDO.getStatus();
        if (currentStatus.equals(updateObj.getStatus())) {
            return; // 状态一致，无需更新
        }
        // 获取太空舱信息
        SpaceCapsuleDO spaceCapsule = spaceCapsuleService.getPayNum(updateReqVO.getPayNum().toString());
        // 根据新状态处理逻辑
        if(updateObj.getStatus().equals(SpaceCapsuleOrderEnum.SPACE_CAPSULE_ORDER_ENUM_APPOINTMENT.getCode())){
            // TODO: 预约逻辑待完成
        }else if(updateObj.getStatus().equals(SpaceCapsuleOrderEnum.SPACE_CAPSULE_ORDER_ENUM_REFUNDED.getCode())){
            handleRefund(updateObj,currentStatus);
            updateObj.setStatus(SpaceCapsuleOrderEnum.SPACE_CAPSULE_ORDER_ENUM_REFUNDED.getCode());
            if(spaceCapsule!=null){
                updateSpaceCapsuleStatus(spaceCapsule, SpaceCapsuleEnum.SPACE_CAPSULE_ENUM_FREE_TIME.getCode());
            }
            updateObj.setOrderEndTime(LocalDateTime.now());
        }else if(updateObj.getStatus().equals(SpaceCapsuleOrderEnum.SPACE_CAPSULE_ORDER_ENUM_DONE.getCode())){
            updateObj.setSpaceCapsuleId(spaceCapsule.getId());
            updateObj.setOrderEndTime(LocalDateTimeUtil.offset(updateObj.getOrderStartTime(), (long) updateObj.getComboNum() *updateObj.getComboMinutes(), ChronoUnit.MINUTES));
            updateSpaceCapsuleStatus(spaceCapsule, SpaceCapsuleEnum.SPACE_CAPSULE_ENUM_FREE_TIME.getCode());
        }else if(updateObj.getStatus().equals(SpaceCapsuleOrderEnum.SPACE_CAPSULE_ORDER_ENUM_IN_USE.getCode())){
            if(currentStatus.equals(SpaceCapsuleOrderEnum.SPACE_CAPSULE_ORDER_ENUM_UNUSED.getCode())
                    &&spaceCapsule.getStatus().equals(SpaceCapsuleEnum.SPACE_CAPSULE_ENUM_IN_USE.getCode())){
                throw exception(ORDER_SPACE_CAPSULE_EXIST);
            }
            updateObj.setSpaceCapsuleId(spaceCapsule.getId());
            updateObj.setSpaceName(spaceCapsule.getSpaceName());
            updateObj.setOrderStartTime(LocalDateTime.now());
            updateSpaceCapsuleStatus(spaceCapsule, SpaceCapsuleEnum.SPACE_CAPSULE_ENUM_IN_USE.getCode());
        }
        // 更新数据库
        orderSpaceCapsuleMapper.updateById(updateObj);
        //单独处理
         if(updateObj.getStatus().equals(SpaceCapsuleOrderEnum.SPACE_CAPSULE_ORDER_ENUM_DONE.getCode()) || updateObj.getStatus().equals(SpaceCapsuleOrderEnum.SPACE_CAPSULE_ORDER_ENUM_REFUNDED.getCode()) ){
             statisticsSpaceCapsuleOrderService.updateStatistics(updateObj);
         }
    }
    // 处理退款逻辑
    private void handleRefund(OrderSpaceCapsuleDO updateObj, Integer currentStatus) {
        MemberUserDO user = userService.getUser(updateObj.getUserId());
        BigDecimal startMoney = user.getMoney();
        // 退款金额计算
        BigDecimal refundAmount = calculateRefundAmount(updateObj, currentStatus);
        updateObj.setRefundMoney(refundAmount);
        // 进行余额退款
        deductionService.reduction(updateObj.getUserId(), refundAmount, BigDecimal.ZERO, refundAmount, BigDecimal.ZERO,updateObj.getCarteenId());
        // 设置变动后的余额
        updateObj.setEndMoney(startMoney.add(refundAmount));
    }
    // 计算退款金额
    private BigDecimal calculateRefundAmount(OrderSpaceCapsuleDO updateObj, Integer currentStatus) {
        // 未使用退款
        if (currentStatus.equals(SpaceCapsuleOrderEnum.SPACE_CAPSULE_ORDER_ENUM_UNUSED.getCode())) {
            return updateObj.getMoney(); // 未使用，全额退款
        }
        // 已使用中途退款
        if (currentStatus.equals(SpaceCapsuleOrderEnum.SPACE_CAPSULE_ORDER_ENUM_IN_USE.getCode())) {
            int comboMinutes = updateObj.getComboMinutes() * updateObj.getComboNum();
            BigDecimal comboPrice = updateObj.getMoney();
            LocalDateTime orderStartTime = updateObj.getOrderStartTime();
            LocalDateTime now = LocalDateTime.now();
            // 计算已使用时间和剩余时间
            long minutesUsed = Duration.between(orderStartTime, now).toMinutes();
            int remainingMinutes = Math.toIntExact(comboMinutes - minutesUsed);
            // 计算每分钟的价格
            BigDecimal pricePerMinute = comboPrice.divide(BigDecimal.valueOf(comboMinutes), 2, RoundingMode.HALF_UP);
            // 计算剩余价格并向下取整
            return pricePerMinute.multiply(BigDecimal.valueOf(remainingMinutes)).setScale(0, RoundingMode.FLOOR);
        }
        return BigDecimal.ZERO; // 默认情况下，无退款
    }
    // 更新太空舱状态
    private void updateSpaceCapsuleStatus(SpaceCapsuleDO spaceCapsule, Integer newStatus) {
        spaceCapsule.setStatus(newStatus);
        spaceCapsuleService.updateSpaceCapsule(spaceCapsule);
    }

    @Override
    public void deleteOrderSpaceCapsule(Long id) {
        // 校验存在
        validateOrderSpaceCapsuleExists(id);
        // 删除
        orderSpaceCapsuleMapper.deleteById(id);
    }

    private void validateOrderSpaceCapsuleExists(Long id) {
        if (orderSpaceCapsuleMapper.selectById(id) == null) {
            throw exception(ORDER_SPACE_CAPSULE_NOT_EXISTS);
        }
    }

    @Override
    public OrderSpaceCapsuleDO getOrderSpaceCapsule(Long id) {
        return orderSpaceCapsuleMapper.selectById(id);
    }

    @Override
    public PageResult<OrderSpaceCapsuleDO> getOrderSpaceCapsulePage(OrderSpaceCapsulePageReqVO pageReqVO) {
        return orderSpaceCapsuleMapper.selectPage(pageReqVO);
    }
    @Override
    public OrderSpaceCapsuleDO openDoor(OrderSpaceCapsuleOperateVo operateVo) {
        Long id = operateVo.getId();
        String zfCode = operateVo.getZfCode();

        SpaceCapsuleDO payNum = spaceCapsuleService.getPayNum(zfCode);
        validateSpaceCapsuleStatus(payNum);

        OrderSpaceCapsuleDO orderSpaceCapsuleDO = orderSpaceCapsuleMapper.selectById(id);
        validateOrderStatus(orderSpaceCapsuleDO);

        if (isFirstOpening(orderSpaceCapsuleDO, payNum)) {
            handleFirstOpening(orderSpaceCapsuleDO, payNum);
        }
        orderSpaceCapsuleDO.setPayNum(payNum.getPayNum());
        orderSpaceCapsuleDO.setMachineNum(payNum.getMachineNum());
        orderSpaceCapsuleMapper.updateById(orderSpaceCapsuleDO);
        return orderSpaceCapsuleDO;
    }

    @Override
    public OrderSpaceCapsuleDO openCmdAdmin(OrderSpaceCapsuleAdminVo adminVo) {
        //判断是0和2
        SpaceCapsuleDO payNum = spaceCapsuleService.getPayNum(adminVo.getZfCode());
        OrderSpaceCapsuleDO capsuleDO=new OrderSpaceCapsuleDO();
        if(adminVo.getType().equals("0")){
            capsuleDO.setComboNum(24);
            capsuleDO.setComboMinutes(60);
            handleFirstOpening(capsuleDO,payNum);
        }else if(adminVo.getType().equals("2")){
            capsuleDO.setComboNum(5);
            capsuleDO.setComboMinutes(1);
            handleFirstOpening(capsuleDO,payNum);
        }
        return capsuleDO;
    }
    public BigDecimal getTotalMoney(Long carTeenId, Date startTime, Date endTime) {
        return orderSpaceCapsuleMapper.selectObjs(
                        new QueryWrapper<OrderSpaceCapsuleDO>()
                                .select("SUM(money) as totalMoney")
                                .eq("carteen_id", carTeenId)
                                .between("create_time", startTime, endTime)
                                .eq("status", SpaceCapsuleOrderEnum.SPACE_CAPSULE_ORDER_ENUM_DONE.getCode())
                ).stream()
                .filter(Objects::nonNull)
                .map(obj -> (BigDecimal) obj)
                .findFirst()
                .orElse(BigDecimal.ZERO);
    }
    // 获取指定时间范围的订单列表
    private List<OrderSpaceCapsuleDO> getOrderList(Long carTeenId, Date startTime, Date endTime) {
        return orderSpaceCapsuleMapper.selectList(
                new LambdaQueryWrapperX<OrderSpaceCapsuleDO>()
                        .eq(OrderSpaceCapsuleDO::getCarteenId, carTeenId)
                        .between(OrderSpaceCapsuleDO::getCreateTime, startTime, endTime)
                        .eq(OrderSpaceCapsuleDO::getStatus, SpaceCapsuleOrderEnum.SPACE_CAPSULE_ORDER_ENUM_DONE.getCode())
                        .orderByAsc(OrderSpaceCapsuleDO::getCreateTime)
        );
    }
    // 计算订单列表的总时长（小时）
    private BigDecimal calculateTotalHours(List<OrderSpaceCapsuleDO> orderSpaceCapsuleDOS) {
        if(orderSpaceCapsuleDOS==null){
            return BigDecimal.ZERO;
        }
        return orderSpaceCapsuleDOS.stream()
                .map(order -> new BigDecimal(order.getComboMinutes() * order.getComboNum()))
                .reduce(BigDecimal.ZERO, BigDecimal::add)
                .divide(new BigDecimal(60), 2, RoundingMode.HALF_UP); // 转换为小时并保留2位小数
    }
    // 获取指定时间范围内的对比数据（时长）
    private List<OrderSpaceCapsuleStatisticsComVo> getComparisonDataHoru(Long carTeenId,List<OrderSpaceCapsuleDO> orderSpaceCapsuleDOS){
        Map<String, List<SpaceCapsuleDO>> collect = spaceCapsuleService.getListByCarteenId(carTeenId).stream().collect(Collectors.groupingBy(SpaceCapsuleDO::getSpaceName));
        Map<Integer, List<OrderSpaceCapsuleDO>> collect1 = orderSpaceCapsuleDOS.stream().collect(Collectors.groupingBy(OrderSpaceCapsuleDO::getPayNum));
        List<OrderSpaceCapsuleStatisticsComVo> list=new ArrayList<>();
        for (Map.Entry<String, List<SpaceCapsuleDO>> entry : collect.entrySet()) {
            OrderSpaceCapsuleStatisticsComVo vo=new OrderSpaceCapsuleStatisticsComVo();
            vo.setDate(entry.getKey());
            List<OrderSpaceCapsuleDO> orderSpaceCapsuleDOS1 = collect1.get(entry.getValue().get(0).getPayNum());
            vo.setTotalMoney(calculateTotalHours(orderSpaceCapsuleDOS1));
            list.add(vo);
        }
        return list;
    }
    private void validateSpaceCapsuleStatus(SpaceCapsuleDO payNum) {
        if (payNum.getStatus().equals(SpaceCapsuleEnum.SPACE_CAPSULE_ENUM_FAULT.getCode())) {
            throw exception(SPACE_CAPSULE_NOT_FAULT);
        }
    }
    private void validateOrderStatus(OrderSpaceCapsuleDO orderSpaceCapsuleDO) {
        Integer status = orderSpaceCapsuleDO.getStatus();
        if (status.equals(SpaceCapsuleOrderEnum.SPACE_CAPSULE_ORDER_ENUM_REFUNDED.getCode()) ||
                status.equals(SpaceCapsuleOrderEnum.SPACE_CAPSULE_ORDER_ENUM_DONE.getCode())) {
            throw exception(ORDER_SPACE_CAPSULE_CLOSE);
        }
    }

    private boolean isFirstOpening(OrderSpaceCapsuleDO orderSpaceCapsuleDO, SpaceCapsuleDO payNum) {
        return orderSpaceCapsuleDO.getStatus().equals(SpaceCapsuleOrderEnum.SPACE_CAPSULE_ORDER_ENUM_UNUSED.getCode()) &&
                payNum.getStatus().equals(SpaceCapsuleEnum.SPACE_CAPSULE_ENUM_FREE_TIME.getCode());
    }

    private void handleFirstOpening(OrderSpaceCapsuleDO orderSpaceCapsuleDO, SpaceCapsuleDO payNum) {
        SpaceCapsuleThreePointsReqVo reqVo = new SpaceCapsuleThreePointsReqVo();
        reqVo.setUUID(payNum.getMachineNum());
        reqVo.setCharge_id(System.currentTimeMillis() / 1000);
        reqVo.setDevice_id(payNum.getPayNum());

        int minute = orderSpaceCapsuleDO.getComboMinutes() * orderSpaceCapsuleDO.getComboNum();
        reqVo.setMinute(minute);

        String body = HttpRequest.post(URL)
                .body(JSONUtil.toJsonStr(reqVo))
                .execute().body();

        JSONObject jsonObject = JSONUtil.parseObj(body);
        if (jsonObject.getInt("status") != 1) {
            throw exception(new ErrorCode(1_004_016_004, jsonObject.getStr("error")));
        }

        String cmd = jsonObject.getStr("cmd");
        orderSpaceCapsuleDO.setCmd(cmd);

        String qrCode = createQrCode("~" + cmd + "~");
        if (qrCode != null) {
            orderSpaceCapsuleDO.setQrCode(qrCode);
        }
    }
    public static String createQrCode(String content){
        // 生成二维码，指定大小
        BufferedImage qrImage = QrCodeUtil.generate(content, 300, 300);
        // 转换为 Base64
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            ImageIO.write(qrImage, "png", baos);
            byte[] imageBytes = baos.toByteArray();
            return "data:image/png;base64,"+Base64.getEncoder().encodeToString(imageBytes);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}