package com.ylx.massage.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ylx.common.exception.ServiceException;
import com.ylx.common.utils.StringUtils;
import com.ylx.massage.domain.CancelOrderApplication;
import com.ylx.massage.domain.TJs;
import com.ylx.massage.domain.TOrder;
import com.ylx.massage.domain.TWxUser;
import com.ylx.massage.enums.OrderStatusEnum;
import com.ylx.massage.service.CancelOrderApplicationService;
import com.ylx.massage.service.TJsService;
import com.ylx.massage.service.TOrderService;
import com.ylx.massage.service.TWxUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * 退单申请服务实现类
 *
 * @author claude
 * @date 2025-01-14
 */
@Slf4j
@Service
public class CancelOrderApplicationServiceImpl
        extends ServiceImpl<com.ylx.massage.mapper.CancelOrderApplicationMapper, CancelOrderApplication>
        implements CancelOrderApplicationService {

    @Autowired
    private TOrderService orderService;

    @Autowired
    private TJsService jsService;

    @Autowired
    private TWxUserService wxUserService;

    /**
     * 创建退单申请
     *
     * @param orderId      订单ID
     * @param cancelReason 退单原因
     * @return String 申请记录ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createApplication(String orderId, String cancelReason) {
        // 查询订单信息
        TOrder order = orderService.getById(orderId);
        if (order == null) {
            throw new ServiceException("订单不存在");
        }

        // 校验订单状态 - 只有进行中的订单才能申请退单
        // 进行中状态包括: 待接单(0)、已接单(1)、已出发(6)、已到达(2)、服务中(3)
        Integer currentStatus = order.getnStatus();
        log.info("订单当前状态：{}", currentStatus);
        if (!isOrderInProgress(currentStatus)) {
            throw new ServiceException("当前订单状态不允许申请退单，只有进行中的订单可以申请退单");
        }

        // 检查是否已有待审核的退单申请
        CancelOrderApplication existingApplication = getInfoByOrderId(orderId);
        if (existingApplication != null && existingApplication.getAuditStatus() == 0) {
            throw new ServiceException("该订单已有待审核的退单申请，请勿重复提交");
        }

        // 查询技师信息
        TJs technician = null;
        if (StringUtils.isNotEmpty(order.getcJsId())) {
            technician = jsService.getById(order.getcJsId());
        }

        // 构建退单申请记录
        CancelOrderApplication application = new CancelOrderApplication();
        application.setOrderId(order.getcId());
        application.setOrderNo(order.getOrderNo());
        application.setOpenId(order.getcOpenId());
        application.setUserName(order.getcName());
        application.setUserPhone(order.getcPhone());
        application.setTechId(order.getcJsId());
        application.setTechName(technician != null ? technician.getcName() : null);
        application.setTechNickName(technician != null ? technician.getcNickName() : null);
        // 设置技师手机号
        application.setTechPhone(technician.getcPhone());

        // 从订单明细中提取项目名称
        String projectName = extractProjectName(order);
        application.setProjectName(projectName);

        // 提取并设置项目时长
        Integer projectDuration = extractProjectDuration(order);
        application.setProjectDuration(projectDuration != null ? String.valueOf(projectDuration) : "0");

        // 计算已服务时长
        Long serviceDuration = calculateServiceDuration(order);
        application.setServiceDuration(String.valueOf(serviceDuration));

        // 设置金额
        application.setOrderAmount(order.getTotalPrice() != null ? order.getTotalPrice() : BigDecimal.ZERO);

        // 计算退款金额
        BigDecimal refundAmount = calculateRefundAmount(order, serviceDuration, projectDuration);
        application.setRefundAmount(refundAmount);

        // 保存订单原始状态，用于取消申请时恢复订单状态
        application.setOrderStatus(currentStatus);

        // 设置申请信息
        application.setAuditStatus(0); // 0：待审核
        application.setApplicationTime(LocalDateTime.now());
        application.setCancelOrderReason(cancelReason);

        // 设置创建时间
        application.setCreateTime(LocalDateTime.now());
        application.setUpdateTime(LocalDateTime.now());

        // 8. 保存退单申请记录
        boolean saved = this.save(application);
        if (!saved) {
            throw new ServiceException("创建退单申请失败");
        }
        log.info("退单申请创建成功，申请ID：{}，订单ID：{}", application.getId(), orderId);
        return application.getId();
    }

    /**
     * 根据订单ID查询退单申请记录
     *
     * @param orderId 订单ID
     * @return CancelOrderApplication 退单申请记录
     */
    @Override
    public CancelOrderApplication getInfoByOrderId(String orderId) {
        LambdaQueryWrapper<CancelOrderApplication> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CancelOrderApplication::getOrderId, orderId);
        return this.getOne(wrapper);
    }

    /**
     * 判断订单是否为进行中状态
     * 进行中状态包括: 待接单(0)、已接单(1)、已出发(6)、已到达(2)、服务中(3)
     *
     * @param status 订单状态
     * @return true-进行中，false-非进行中
     */
    private boolean isOrderInProgress(Integer status) {
        return status != null &&
                (status.equals(OrderStatusEnum.WAIT_JD.getCode()) || // 待接单
                        status.equals(OrderStatusEnum.RECEIVED_ORDER.getCode()) || // 已接单
                        status.equals(OrderStatusEnum.DEPART.getCode()) || // 已出发
                        status.equals(OrderStatusEnum.ARRIVED.getCode()) || // 已到达
                        status.equals(OrderStatusEnum.SERVICE.getCode())); // 服务中
    }

    /**
     * 从订单中提取项目名称
     *
     * @param order 订单对象
     * @return String 项目名称
     */
    private String extractProjectName(TOrder order) {
        try {
            if (order.getcGoods() != null && !order.getcGoods().isEmpty()) {
                // cGoods是JSONArray，解析第一个项目的名称
                return order.getcGoods().getJSONObject(0).getString("cTitle");
            }
        } catch (Exception e) {
            log.warn("解析订单项目名称失败，订单ID：{}", order.getcId(), e);
        }
        return null;
    }

    /**
     * 计算已服务时长（分钟）
     *
     * @param order 订单对象
     * @return Long 已服务时长（分钟）
     */
    private Long calculateServiceDuration(TOrder order) {
        try {
            LocalDateTime startTime = order.getStartTime();
            LocalDateTime endTime = order.getEndTime();

            if (startTime != null && endTime != null) {
                long minutes = Duration.between(startTime, endTime).toMinutes();
                if (minutes > 0) {
                    return minutes;
                }
            } else if (startTime != null) {
                // 如果只有开始时间，计算到现在的时长
                long minutes = Duration.between(startTime, LocalDateTime.now()).toMinutes();
                if (minutes > 0) {
                    return minutes;
                }
            }
        } catch (Exception e) {
            log.warn("计算服务时长失败，订单ID：{}", order.getcId(), e);
        }
        return 0L;
    }

    /**
     * 从订单中提取项目时长（分钟）
     *
     * @param order 订单对象
     * @return Integer 项目时长（分钟）
     */
    private Integer extractProjectDuration(TOrder order) {
        try {
            if (order.getcGoods() != null && !order.getcGoods().isEmpty()) {
                long totalMinutes = 0;
                for (int i = 0; i < order.getcGoods().size(); i++) {
                    JSONObject item = order.getcGoods().getJSONObject(i);
                    Integer minutes = item.getInteger("nMinute");
                    Integer number = item.getInteger("number");
                    if (minutes != null && number != null) {
                        totalMinutes += (minutes * number);
                    }
                }
                return (int) totalMinutes;
            }
        } catch (Exception e) {
            log.warn("解析订单项目时长失败，订单ID：{}", order.getcId(), e);
        }
        return null;
    }

    /**
     * 计算退款金额
     * <p>
     * 退款规则：
     * （1）订单已接单状态：技师未出发，不需要填写退单申请即可退款，退款比例100%
     * （2）订单已到达之前状态（待接单、已接单、已出发）：
     * 1）免车费-需要填写退单申请，退款比例100%（自动带出，人工审核）
     * 2）有车费-需要填写退单申请，退款金额=（项目金额-优惠金额）*100%+车费（自动带出，人工审核）
     * （3）订单服务中：
     * 1）免车费-需要填写退单申请，退款金额=（项目金额-优惠金额）*（服务时长/项目时长）100%（自动带出，人工审核）
     * 2）有车费-需要填写退单申请，退款金额=（项目金额-优惠金额）*（服务时长/项目时长）100%+车费（自动带出，人工审核）
     *
     * @param order           订单对象
     * @param serviceDuration 已服务时长（分钟）
     * @param projectDuration 项目时长（分钟）
     * @return BigDecimal 退款金额
     */
    private BigDecimal calculateRefundAmount(TOrder order, Long serviceDuration, Integer projectDuration) {
        Integer orderStatus = order.getnStatus();
        // 获取订单基础金额
        // 项目金额
        BigDecimal projectAmount = order.getdTotalMoney() != null ? order.getdTotalMoney() : BigDecimal.ZERO;
        // 优惠金额
        BigDecimal preferential = order.getPreferential() != null ? order.getPreferential() : BigDecimal.ZERO;
        // 车费
        BigDecimal fare = order.getFare() != null ? order.getFare() : BigDecimal.ZERO;

        // 项目金额 - 优惠金额
        BigDecimal projectAmountAfterDiscount = projectAmount.subtract(preferential);

        // 判断是否有车费
        boolean hasCarFee = fare.compareTo(BigDecimal.ZERO) > 0;

        BigDecimal refundAmount = new BigDecimal("0");
        if (OrderStatusEnum.RECEIVED_ORDER.getCode().equals(orderStatus)) {
            // （1）订单已接单状态：技师未出发，退款比例100%
            // 退款金额 = 项目金额 - 优惠金额 + 车费（如果有）
            refundAmount = projectAmountAfterDiscount.add(fare);
            log.info("订单已接单状态，退款金额=项目金额({})-优惠金额({})+车费({})={}", projectAmount, preferential, fare, refundAmount);
        } else if (OrderStatusEnum.DEPART.getCode().equals(orderStatus)) {
            // （2）订单已出发状态（已到达之前）
            if (hasCarFee) {
                //有车费：退款金额 = （项目金额 - 优惠金额）* 100% + 车费
                refundAmount = projectAmountAfterDiscount.add(fare);
                log.info("订单已出发状态且有车费，退款金额=（项目金额({})-优惠金额({}）*100%+车费({})={}", projectAmount, preferential, fare, refundAmount);
            } else {
                //免车费：退款比例100%
                refundAmount = projectAmountAfterDiscount;
                log.info("订单已出发状态且免车费，退款金额=（项目金额({})-优惠金额({}）*100%={}", projectAmount, preferential, refundAmount);
            }
        } else if (OrderStatusEnum.SERVICE.getCode().equals(orderStatus)) {
            // （3）订单服务中
            // 计算服务比例：服务时长 / 项目时长
            double serviceRatio = (double) serviceDuration / projectDuration;
            // 确保比例不超过1（不超过100%）
            serviceRatio = Math.min(serviceRatio, 1.0);

            // 计算退款金额
            BigDecimal serviceRefundAmount = projectAmountAfterDiscount.multiply(BigDecimal.valueOf(serviceRatio)).setScale(2, BigDecimal.ROUND_HALF_UP);
            if (hasCarFee) {
                //有车费：退款金额 = （项目金额 - 优惠金额）*（服务时长/项目时长）100% + 车费
                refundAmount = serviceRefundAmount.add(fare);
                log.info("订单服务中且有车费，退款金额=（项目金额({})-优惠金额({}）*({}/{})*100%+车费({})={}", projectAmount, preferential, serviceDuration, projectDuration, fare, refundAmount);
            } else {
                //免车费：退款金额 = （项目金额 - 优惠金额）*（服务时长/项目时长）100%
                refundAmount = serviceRefundAmount;
                log.info("订单服务中且免车费，退款金额=（项目金额({})-优惠金额({}）*({}/{})*100%={}", projectAmount, preferential, serviceDuration, projectDuration, refundAmount);
            }
        }

        // 确保退款金额不超过订单总价
        BigDecimal maxRefund = order.getTotalPrice() != null ? order.getTotalPrice() : BigDecimal.ZERO;
        if (refundAmount.compareTo(maxRefund) > 0) {
            log.warn("计算退款金额({})超过订单总价({})，调整为订单总价", refundAmount, maxRefund);
            refundAmount = maxRefund;
        }
        // 确保退款金额不为负数
        if (refundAmount.compareTo(BigDecimal.ZERO) < 0) {
            log.warn("计算退款金额({})为负数，调整为0", refundAmount);
            refundAmount = BigDecimal.ZERO;
        }
        log.info("最终退款金额：{}，订单ID：{}，订单状态：{}，服务时长：{}分钟，项目时长：{}分钟", refundAmount, order.getcId(), orderStatus, serviceDuration, projectDuration);
        return refundAmount;
    }

    /**
     * 取消退单申请
     * <p>
     * 业务流程：
     * 1. 验证退单申请是否存在
     * 2. 验证退单申请状态是否为待审核（只有待审核的申请才能取消）
     * 3. 更新退单申请记录的审核状态为已取消（使用 auditStatus = 3 表示用户主动取消）
     * 4. 返回操作结果（订单状态的恢复由调用方 TOrderService 处理）
     *
     * @param orderId 订单ID
     * @return Boolean 操作结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean cancelApplication(String orderId) {
        log.info("开始取消退单申请，订单ID：{}", orderId);

        // 1. 查询退单申请记录
        CancelOrderApplication application = getInfoByOrderId(orderId);
        if (application == null) {
            throw new ServiceException("退单申请不存在");
        }

        // 2. 验证退单申请状态 - 只有待审核的申请才能取消
        if (application.getAuditStatus() != 0) {
            throw new ServiceException("当前退单申请状态不允许取消，只有待审核的申请可以取消");
        }

        // 3. 更新退单申请记录状态为已取消
        // 使用 auditStatus = 3 表示用户主动取消（区别于审核拒绝的 2）
        application.setAuditStatus(2);
        application.setUpdateTime(LocalDateTime.now());
        boolean updated = this.updateById(application);
        if (!updated) {
            throw new ServiceException("取消退单申请失败");
        }
        log.info("退单申请取消成功，订单ID：{}，申请ID：{}", orderId, application.getId());
        return Boolean.TRUE;
    }
}
