package shop.alien.store.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import shop.alien.entity.store.StoreBookingCategory;
import shop.alien.entity.store.StoreBookingTable;
import shop.alien.entity.store.UserReservation;
import shop.alien.entity.store.UserReservationTable;
import shop.alien.entity.store.vo.ReservationOrderCountsDto;
import shop.alien.entity.store.vo.ReservationOrderListDto;
import shop.alien.mapper.UserReservationOrderMapper;
import shop.alien.mapper.UserReservationTableMapper;
import shop.alien.store.service.ReservationOrderListService;
import shop.alien.store.service.StoreBookingCategoryService;
import shop.alien.store.service.StoreBookingTableService;
import shop.alien.store.service.UserReservationService;
import shop.alien.store.vo.ReservationOrderListResultVo;
import shop.alien.store.vo.ReservationOrderListVo;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 预订订单列表：店铺名称模糊搜索（限10字）、展示店铺名/入口图/状态/预订信息
 *
 * @author system
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ReservationOrderListServiceImpl implements ReservationOrderListService {

    private static final int STORE_NAME_SEARCH_MAX_LEN = 10;
    private static final int ORDER_STATUS_UNPAID = 0;
    private static final int ORDER_STATUS_TO_USE = 1;
    private static final int ORDER_STATUS_COMPLETED = 2;
    private static final int ORDER_STATUS_EXPIRED = 3;
    private static final int ORDER_STATUS_CANCELLED = 4;
    private static final int ORDER_STATUS_CLOSED = 5;
    private static final int ORDER_STATUS_REFUNDING = 6;
    private static final int ORDER_STATUS_REFUNDED = 7;

    private final UserReservationOrderMapper userReservationOrderMapper;
    private final UserReservationService userReservationService;
    private final UserReservationTableMapper userReservationTableMapper;
    private final StoreBookingTableService storeBookingTableService;
    private final StoreBookingCategoryService storeBookingCategoryService;

    @Override
    public ReservationOrderListResultVo listPage(Integer userId, String storeName, Integer orderStatus, long current, long size) {
        ReservationOrderListResultVo result = new ReservationOrderListResultVo();
        if (userId == null) {
            result.setList(new Page<>(current, size));
            result.setCountAll(0);
            result.setCountToUse(0);
            result.setCountCompleted(0);
            result.setCountRefunded(0);
            return result;
        }
        ReservationOrderCountsDto counts = userReservationOrderMapper.selectOrderCountsByUserId(userId);
        result.setCountAll(counts.getCountAll());
        result.setCountToUse(counts.getCountToUse());
        result.setCountCompleted(counts.getCountCompleted());
        result.setCountRefunded(counts.getCountRefunded());

        String searchStoreName = null;
        if (StringUtils.isNotBlank(storeName)) {
            searchStoreName = storeName.trim();
            if (searchStoreName.length() > STORE_NAME_SEARCH_MAX_LEN) {
                searchStoreName = searchStoreName.substring(0, STORE_NAME_SEARCH_MAX_LEN);
            }
        }
        Page<ReservationOrderListDto> page = new Page<>(current, size);
        IPage<ReservationOrderListDto> dtoPage = userReservationOrderMapper.selectOrderListPage(page, userId, searchStoreName, orderStatus);
        List<ReservationOrderListDto> records = dtoPage.getRecords();
        if (records == null || records.isEmpty()) {
            IPage<ReservationOrderListVo> voPage = new Page<>(dtoPage.getCurrent(), dtoPage.getSize(), dtoPage.getTotal());
            voPage.setRecords(Collections.emptyList());
            result.setList(voPage);
            return result;
        }
        Set<Integer> reservationIds = records.stream()
                .map(ReservationOrderListDto::getReservationId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        Map<Integer, UserReservation> reservationMap = new HashMap<>();
        if (!reservationIds.isEmpty()) {
            for (UserReservation r : userReservationService.listByIds(reservationIds)) {
                reservationMap.put(r.getId(), r);
            }
        }
        Map<Integer, String> categoryNameMap = new HashMap<>();
        Map<Integer, String> reservationTableTextMap = new HashMap<>();
        for (Integer rid : reservationIds) {
            UserReservation r = reservationMap.get(rid);
            if (r == null) continue;
            List<UserReservationTable> utList = userReservationTableMapper.selectList(
                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<UserReservationTable>()
                            .eq(UserReservationTable::getReservationId, rid)
                            .orderByAsc(UserReservationTable::getSort)
                            .orderByAsc(UserReservationTable::getId));
            List<StoreBookingTable> tables = new ArrayList<>();
            String categoryName = null;
            for (UserReservationTable ut : utList) {
                StoreBookingTable t = storeBookingTableService.getById(ut.getTableId());
                if (t != null) {
                    tables.add(t);
                    if (categoryName == null && t.getCategoryId() != null) {
                        StoreBookingCategory cat = storeBookingCategoryService.getById(t.getCategoryId());
                        if (cat != null) categoryName = cat.getCategoryName();
                    }
                }
            }
            String tableNumbersText = tables.stream().map(StoreBookingTable::getTableNumber).filter(Objects::nonNull).collect(Collectors.joining(","));
            reservationTableTextMap.put(rid, tableNumbersText.isEmpty() ? null : tableNumbersText);
            categoryNameMap.put(rid, categoryName != null ? categoryName : "大厅");
        }

        List<ReservationOrderListVo> voList = new ArrayList<>();
        for (ReservationOrderListDto dto : records) {
            ReservationOrderListVo vo = new ReservationOrderListVo();
            vo.setOrderId(dto.getOrderId());
            vo.setOrderSn(dto.getOrderSn());
            vo.setStoreId(dto.getStoreId());
            vo.setBusinessSection(dto.getBusinessSection());
            vo.setStoreName(dto.getStoreName());
            vo.setStoreEntranceImageUrl(dto.getStoreEntranceImageUrl());
            vo.setOrderStatus(dto.getOrderStatus());
            vo.setPaymentStatus(dto.getPaymentStatus());
            UserReservation resForStatus = dto.getReservationId() != null ? reservationMap.get(dto.getReservationId()) : null;
            vo.setStatusText(buildStatusText(dto.getOrderStatus(), resForStatus));
            vo.setDepositAmount(dto.getDepositAmount());
            vo.setVerificationCode(dto.getVerificationCode());
            vo.setOutTradeNo(dto.getOutTradeNo());
            vo.setPayType(dto.getPayType());
            vo.setMerchantCancelReason(dto.getMerchantCancelReason());
            vo.setCreatedTime(dto.getCreatedTime());
            vo.setCanContinuePay(false);
            vo.setCanCancelReservation(false);
            vo.setCanModifyReservation(false);
            vo.setCanViewVoucher(false);
            vo.setCanDelete(false);
            vo.setCanBookAgain(false);
            vo.setOrderCostType(dto.getOrderCostType());
            Integer status = dto.getOrderStatus();
            if (status != null) {
                vo.setCanContinuePay(ORDER_STATUS_UNPAID == status);
                vo.setCanCancelReservation(ORDER_STATUS_UNPAID == status || ORDER_STATUS_TO_USE == status);
                vo.setCanModifyReservation(ORDER_STATUS_TO_USE == status);
                vo.setCanViewVoucher(ORDER_STATUS_TO_USE == status);
                boolean endState = status == ORDER_STATUS_COMPLETED || status == ORDER_STATUS_EXPIRED
                        || status == ORDER_STATUS_CANCELLED || status == ORDER_STATUS_CLOSED
                        || status == ORDER_STATUS_REFUNDING || status == ORDER_STATUS_REFUNDED;
                vo.setCanDelete(endState);
                vo.setCanBookAgain(endState);
            }

            UserReservation res = resForStatus;
            if (res != null) {
                vo.setReservationDateText(formatReservationDateWithWeekday(res.getReservationDate()));
                String catName = categoryNameMap.get(res.getId());
                int guestCount = res.getGuestCount() != null ? res.getGuestCount() : 0;
                vo.setGuestAndCategoryText((catName != null ? catName : "大厅") + " " + guestCount + "人");
                vo.setTableNumbersText(reservationTableTextMap.get(res.getId()));
                vo.setDiningTimeSlotText(buildDiningTimeSlot(res.getStartTime(), res.getEndTime()));
            }

            voList.add(vo);
        }

        IPage<ReservationOrderListVo> voPage = new Page<>(dtoPage.getCurrent(), dtoPage.getSize(), dtoPage.getTotal());
        voPage.setRecords(voList);
        result.setList(voPage);
        return result;
    }

    /**
     * 状态文案。orderStatus=4 时根据 user_reservation.reason 区分：reason 不为空为「商家取消」，否则「用户取消」
     */
    private static String buildStatusText(Integer orderStatus, UserReservation reservation) {
        if (orderStatus == null) return "";
        if (orderStatus == 4) {
            if (reservation!=null&&StringUtils.isNotBlank(reservation.getReason())){
                return "商家取消";
            } else {
                return "用户取消";
            }
        }
        switch (orderStatus) {
            case 0: return "待支付";
            case 1: return "待使用";
            case 2: return "已完成";
            case 3: return "已过期";
            case 5: return "已关闭";
            case 6: return "退款中";
            case 7: return "已退款";
            default: return "";
        }
    }

    private static String formatReservationDateWithWeekday(Date date) {
        if (date == null) return null;
        SimpleDateFormat f = new SimpleDateFormat("MM月dd日", Locale.CHINA);
        String s = f.format(date);
        Calendar c = Calendar.getInstance(Locale.CHINA);
        c.setTime(date);
        String[] weekDays = {"周日", "周一", "周二", "周三", "周四", "周五", "周六"};
        int w = c.get(Calendar.DAY_OF_WEEK) - 1;
        if (w < 0) w = 0;
        s += "(" + weekDays[w] + ")";
        return s;
    }

    private static String buildDiningTimeSlot(String startTime, String endTime) {
        if (startTime == null && endTime == null) return null;
        if (startTime != null && endTime != null) return startTime + "-" + endTime;
        return startTime != null ? startTime : endTime;
    }
}
