package com.jeesharp.business.modules.food.application.support;

import com.jeesharp.business.modules.common.enums.VerticalPayStatusEnum;

import com.jeesharp.business.modules.common.enums.ShelfStatusEnum;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.jeesharp.business.modules.food.dto.FoodBookingCreateDTO;
import com.jeesharp.business.modules.food.entity.FoodBookingOrder;
import com.jeesharp.business.modules.food.entity.FoodPackage;
import com.jeesharp.business.modules.food.entity.FoodRestaurant;
import com.jeesharp.business.modules.food.enums.FoodBookingStatusEnum;

import com.jeesharp.business.modules.common.enums.OnlineEnabledEnum;

import com.jeesharp.business.modules.food.service.FoodPackageService;
import com.jeesharp.business.modules.food.service.FoodRestaurantService;
import com.jeesharp.business.modules.food.vo.FoodBookingResultVO;
import com.jeesharp.framework.exception.BizErrorException;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;

/**
 * 美食团购预约创建编排：校验门店/套餐、扣减库存并组装待落库垂直单。
 *
 * @author jeesharp
 * @since 2026-06-09
 */
@Component
@AllArgsConstructor
public class FoodBookingCreateAssembler {

    private static final String TRADE_ORDER_PREFIX = "FOOD";
    private static final String DEFAULT_MEMBER_ID = "-";
    private static final String EMPTY_JSON_OBJECT = "{}";
    private static final int VERIFY_CODE_LENGTH = 8;
    private static final int MIN_BOOKING_QUANTITY = 1;
    private static final int DEFAULT_MAX_QUANTITY_PER_ORDER = 20;
    private static final DateTimeFormatter DT_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final String MSG_INVALID_QTY = "预约数量不合法";
    private static final String MSG_REST_NOT_FOUND = "门店不存在";
    private static final String MSG_REST_OFFLINE = "门店已下线";
    private static final String MSG_PKG_NOT_FOUND = "套餐不存在";
    private static final String MSG_PKG_MISMATCH = "套餐与门店不匹配";
    private static final String MSG_PKG_OFFLINE = "套餐已下线";
    private static final String MSG_PKG_ONLINE_ORDER_DISABLED = "该套餐暂未开放在线购买";
    private static final String MSG_EXCEED_MAX_QTY = "超过单次可购买份数";
    private static final String MSG_STOCK_INSUFFICIENT = "库存不足，请减少份数或稍后重试";

    private final FoodRestaurantService foodRestaurantService;
    private final FoodPackageService foodPackageService;

    /**
     * 校验入参、扣减可售库存并返回待持久化的垂直单实体（含结果 JSON 快照）。
     */
    public FoodBookingOrder buildBookingOrder(FoodBookingCreateDTO dto) {
        if (dto.getQuantity() == null || dto.getQuantity() < MIN_BOOKING_QUANTITY) {
            throw new BizErrorException(MSG_INVALID_QTY);
        }
        FoodRestaurant restaurant = foodRestaurantService.get(dto.getRestaurantId());
        if (restaurant == null) {
            throw new BizErrorException(MSG_REST_NOT_FOUND);
        }
        if (!ShelfStatusEnum.ONLINE.getValue().equals(restaurant.getStatus())) {
            throw new BizErrorException(MSG_REST_OFFLINE);
        }
        FoodPackage pkg = foodPackageService.get(dto.getPackageId());
        if (pkg == null) {
            throw new BizErrorException(MSG_PKG_NOT_FOUND);
        }
        if (!dto.getRestaurantId().equals(pkg.getRestaurantId())) {
            throw new BizErrorException(MSG_PKG_MISMATCH);
        }
        if (!ShelfStatusEnum.ONLINE.getValue().equals(pkg.getStatus())) {
            throw new BizErrorException(MSG_PKG_OFFLINE);
        }
        Integer onlineOrder = pkg.getOnlineOrderEnabled();
        if (onlineOrder != null && OnlineEnabledEnum.DISABLED.getValue().equals(onlineOrder)) {
            throw new BizErrorException(MSG_PKG_ONLINE_ORDER_DISABLED);
        }
        int quantity = dto.getQuantity();
        int maxAllowed = resolveMaxQuantityPerOrder(pkg);
        if (quantity > maxAllowed) {
            throw new BizErrorException(MSG_EXCEED_MAX_QTY);
        }
        foodPackageService.decrementAvailableQuantityIfConfigured(pkg, quantity);

        FoodBookingOrder entity = new FoodBookingOrder();
        entity.setId(IdUtil.getSnowflakeNextIdStr());
        entity.setTradeOrderId(TRADE_ORDER_PREFIX + compactUuid());
        entity.setRestaurantId(dto.getRestaurantId());
        entity.setPackageId(dto.getPackageId());
        entity.setMemberId(StrUtil.blankToDefault(dto.getMemberId(), DEFAULT_MEMBER_ID));
        entity.setQuantity(quantity);
        entity.setGuestPhone(dto.getGuestPhone());
        entity.setVerifyCode(compactUuid().substring(0, VERIFY_CODE_LENGTH).toUpperCase());
        entity.setPayStatus(VerticalPayStatusEnum.UNPAID.getValue());
        entity.setBookStatus(FoodBookingStatusEnum.PENDING_PAY.getValue());
        inheritMerchantTenant(entity, restaurant);
        BigDecimal unit = pkg.getPrice() == null ? BigDecimal.ZERO : pkg.getPrice();
        BigDecimal total = unit.multiply(BigDecimal.valueOf(entity.getQuantity()));
        FoodBookingResultVO vo = buildResultVo(entity.getId(), restaurant, pkg, entity.getQuantity(), total,
                entity.getVerifyCode(), entity.getBookStatus(), entity.getPayStatus());
        entity.setResultPayloadJson(JSONUtil.toJsonStr(vo));
        return entity;
    }

    private static FoodBookingResultVO buildResultVo(String orderId, FoodRestaurant restaurant, FoodPackage pkg, int qty,
                                                     BigDecimal total, String verifyCode, String bookStatus,
                                                     String payStatus) {
        FoodBookingResultVO vo = new FoodBookingResultVO();
        vo.setOrderId(orderId);
        vo.setVerifyCode(verifyCode);
        vo.setStatus(bookStatus);
        vo.setPayStatus(payStatus);
        vo.setTitle(restaurant.getName() + " · " + pkg.getName() + " · " + qty + "份");
        vo.setAmountLabel(formatAmountLabel(total));
        vo.setAmount(total);
        vo.setStatusLabel(FoodBookingStatusEnum.getDescByValue(bookStatus));
        vo.setCreatedAt(LocalDateTime.now().format(DT_FMT));
        vo.setResultPayloadJson(EMPTY_JSON_OBJECT);
        return vo;
    }

    private static void inheritMerchantTenant(FoodBookingOrder order, FoodRestaurant merchant) {
        if (order == null || merchant == null) {
            return;
        }
        order.setTenantCode(merchant.getTenantCode());
        order.setTenantId(merchant.getTenantId());
        order.closeTenantCodeAutoSet();
    }

    private static String formatAmountLabel(BigDecimal total) {
        if (total == null || total.compareTo(BigDecimal.ZERO) == 0) {
            return "¥0";
        }
        return "¥" + total.stripTrailingZeros().toPlainString();
    }

    private static int resolveMaxQuantityPerOrder(FoodPackage pkg) {
        Integer m = pkg.getMaxQuantityPerOrder();
        return m != null && m > 0 ? m : DEFAULT_MAX_QUANTITY_PER_ORDER;
    }

    private static String compactUuid() {
        return UUID.randomUUID().toString().replace("-", "");
    }
}
