package shop.alien.store.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.beans.BeanUtils;
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.StoreBookingTableVo;
import shop.alien.mapper.StoreBookingTableMapper;
import shop.alien.mapper.UserReservationMapper;
import shop.alien.mapper.UserReservationTableMapper;
import shop.alien.store.service.StoreBookingCategoryService;
import shop.alien.store.service.StoreBookingTableService;
import shop.alien.util.common.JwtUtil;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 预订服务桌号表 服务实现类
 *
 * @author system
 * @since 2025-01-XX
 */
@Slf4j
@Service
@Transactional
public class StoreBookingTableServiceImpl extends ServiceImpl<StoreBookingTableMapper, StoreBookingTable> implements StoreBookingTableService {

    private final StoreBookingCategoryService storeBookingCategoryService;
    private final UserReservationTableMapper userReservationTableMapper;
    private final UserReservationMapper userReservationMapper;

    public StoreBookingTableServiceImpl(@Lazy StoreBookingCategoryService storeBookingCategoryService,
                                        UserReservationTableMapper userReservationTableMapper,
                                        UserReservationMapper userReservationMapper) {
        this.storeBookingCategoryService = storeBookingCategoryService;
        this.userReservationTableMapper = userReservationTableMapper;
        this.userReservationMapper = userReservationMapper;
    }

    @Override
    public List<StoreBookingTable> getTableList(Integer storeId, Integer categoryId) {
        log.info("StoreBookingTableServiceImpl.getTableList?storeId={}, categoryId={}", storeId, categoryId);
        
        LambdaQueryWrapper<StoreBookingTable> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreBookingTable::getStoreId, storeId);
        
        // 如果指定了分类ID，则按分类筛选；否则查询全部
        if (categoryId != null) {
            wrapper.eq(StoreBookingTable::getCategoryId, categoryId);
        }
        
        // 查询所有数据，然后在Java中进行排序
        List<StoreBookingTable> list = this.list(wrapper);
        
        // 自定义排序：根据类别、字母(A-Z)、数字(由小到大)顺序排列
        list.sort(Comparator
                .comparing(StoreBookingTable::getCategoryId, Comparator.nullsLast(Integer::compareTo)) // 先按类别排序
                .thenComparing(table -> parseTableNumberForSort(table.getTableNumber()))); // 再按桌号排序
        
        return list;
    }

    @Override
    public List<StoreBookingTableVo> getTableListWithCategoryName(Integer storeId, Integer categoryId) {
        log.info("StoreBookingTableServiceImpl.getTableListWithCategoryName?storeId={}, categoryId={}", storeId, categoryId);
        
        // 先查询桌号列表
        List<StoreBookingTable> tableList = getTableList(storeId, categoryId);
        
        // 查询所有分类信息，构建categoryId -> categoryName的映射
        List<StoreBookingCategory> categoryList = storeBookingCategoryService.list(
                new LambdaQueryWrapper<StoreBookingCategory>()
                        .eq(StoreBookingCategory::getStoreId, storeId)
        );
        Map<Integer, String> categoryMap = categoryList.stream()
                .collect(Collectors.toMap(
                        StoreBookingCategory::getId,
                        StoreBookingCategory::getCategoryName,
                        (v1, v2) -> v1 // 如果有重复key，保留第一个
                ));
        
        // 转换为VO并设置分类名称
        return tableList.stream()
                .filter(table -> table != null)
                .map(table -> {
                    StoreBookingTableVo vo = new StoreBookingTableVo();
                    BeanUtils.copyProperties(table, vo);
                    // 设置分类名称
                    if (table.getCategoryId() != null) {
                        vo.setCategoryName(categoryMap.get(table.getCategoryId()));
                    }
                    return vo;
                })
                .collect(Collectors.toList());
    }

    @Override
    public IPage<StoreBookingTableVo> getTableListPage(Integer pageNum, Integer pageSize, Integer storeId, Integer categoryId) {
        log.info("StoreBookingTableServiceImpl.getTableListPage?pageNum={}, pageSize={}, storeId={}, categoryId={}", 
                pageNum, pageSize, storeId, categoryId);
        
        // 先查询所有数据（因为需要自定义排序）
        List<StoreBookingTableVo> allList = getTableListWithCategoryName(storeId, categoryId);
        
        // 计算分页信息
        int total = allList.size();
        int start = (pageNum - 1) * pageSize;
        int end = Math.min(start + pageSize, total);
        
        // 手动分页
        List<StoreBookingTableVo> pageList;
        if (start >= total) {
            pageList = java.util.Collections.emptyList();
        } else {
            pageList = allList.subList(start, end);
        }
        
        // 构建分页对象
        IPage<StoreBookingTableVo> page = new Page<>(pageNum, pageSize, total);
        page.setRecords(pageList);
        
        return page;
    }
    
    /**
     * 解析桌号用于排序
     * 规则：字母(A-Z)优先，然后数字(由小到大)
     * 排序逻辑：
     * 1. 纯数字桌号（如：1, 2, 10）按数字从小到大排序
     * 2. 字母桌号（如：A1, B2）按字母A-Z排序，然后按数字从小到大排序
     * 3. 字母桌号优先于纯数字桌号
     * 
     * @param tableNumber 桌号
     * @return 排序键
     */
    private String parseTableNumberForSort(String tableNumber) {
        if (tableNumber == null || tableNumber.isEmpty()) {
            return "ZZZZZZZZZZ9999999999"; // 空值排在最后
        }
        
        // 去除空格并转为大写，便于比较
        String normalized = tableNumber.trim().toUpperCase();
        
        // 分离字母和数字部分
        StringBuilder letters = new StringBuilder();
        StringBuilder numbers = new StringBuilder();
        
        for (char c : normalized.toCharArray()) {
            if (Character.isLetter(c)) {
                letters.append(c);
            } else if (Character.isDigit(c)) {
                numbers.append(c);
            }
        }
        
        String letterPart = letters.toString();
        String numberPart = numbers.toString();
        
        // 数字部分处理：转换为整数再格式化，确保数字排序正确（如：1 < 2 < 10）
        if (numberPart.isEmpty()) {
            numberPart = "0000000000";
        } else {
            try {
                int num = Integer.parseInt(numberPart);
                numberPart = String.format("%010d", num); // 补零到10位，确保数字排序正确
            } catch (NumberFormatException e) {
                // 如果数字太大超出int范围，保持原样并补零
                numberPart = String.format("%-10s", numberPart).replace(' ', '0');
            }
        }
        
        // 字母部分处理
        if (letterPart.isEmpty()) {
            // 纯数字桌号：使用特殊前缀确保排在字母桌号后面
            // 但根据用户需求，可能需要纯数字排在前面，这里先按字母优先的逻辑
            letterPart = "ZZZZZZZZZZ"; // 纯数字排在字母后面
        } else {
            // 字母桌号：补空格到固定长度，确保字母排序正确
            letterPart = String.format("%-10s", letterPart);
        }
        
        return letterPart + numberPart;
    }

    @Override
    public boolean addTable(StoreBookingTable table) {
        log.info("StoreBookingTableServiceImpl.addTable?table={}", table);
        
        // 从JWT获取当前登录用户ID
        Integer userId = getCurrentUserId();
        
        // 参数验证
        if (table.getStoreId() == null) {
            log.warn("新增预订服务桌号失败：门店ID不能为空");
            throw new RuntimeException("门店ID不能为空");
        }
        if (table.getCategoryId() == null) {
            log.warn("新增预订服务桌号失败：分类ID不能为空");
            throw new RuntimeException("分类ID不能为空");
        }
        if (!StringUtils.hasText(table.getTableNumber())) {
            log.warn("新增预订服务桌号失败：桌号不能为空");
            throw new RuntimeException("桌号不能为空");
        }
        if (table.getSeatingCapacity() == null || table.getSeatingCapacity() <= 0) {
            log.warn("新增预订服务桌号失败：座位数必须大于0");
            throw new RuntimeException("座位数必须大于0");
        }
        
        // 处理桌号：去除前后空格
        String tableNumber = table.getTableNumber().trim();
        table.setTableNumber(tableNumber);
        
        // 检查同一分类下是否已存在相同的桌号（不同分类可以同名）
        LambdaQueryWrapper<StoreBookingTable> checkWrapper = new LambdaQueryWrapper<>();
        checkWrapper.eq(StoreBookingTable::getStoreId, table.getStoreId())
                .eq(StoreBookingTable::getCategoryId, table.getCategoryId())
                .eq(StoreBookingTable::getTableNumber, tableNumber);
        // @TableLogic 会自动过滤已删除的记录（delete_flag=0）
        StoreBookingTable existingTable = this.getOne(checkWrapper);
        if (existingTable != null) {
            log.warn("新增预订服务桌号失败：同一分类下桌号已存在，storeId={}, categoryId={}, tableNumber={}", 
                    table.getStoreId(), table.getCategoryId(), tableNumber);
            throw new RuntimeException("此桌号已存在");
        }
        
        table.setCreatedUserId(userId);
        
        return this.save(table);
    }

    @Override
    public boolean batchAddTables(Integer storeId, Integer categoryId, List<StoreBookingTable> tables) {
        log.info("StoreBookingTableServiceImpl.batchAddTables?storeId={}, categoryId={}, tables.size={}", 
                storeId, categoryId, tables != null ? tables.size() : 0);
        
        // 从JWT获取当前登录用户ID
        Integer userId = getCurrentUserId();
        
        // 参数验证
        if (storeId == null) {
            log.warn("批量新增预订服务桌号失败：门店ID不能为空");
            throw new RuntimeException("门店ID不能为空");
        }
        if (categoryId == null) {
            log.warn("批量新增预订服务桌号失败：分类ID不能为空");
            throw new RuntimeException("分类ID不能为空");
        }
        if (tables == null || tables.isEmpty()) {
            log.warn("批量新增预订服务桌号失败：桌号列表不能为空");
            throw new RuntimeException("桌号列表不能为空");
        }
        
        // 验证并处理每个桌号
        for (StoreBookingTable table : tables) {
            if (!StringUtils.hasText(table.getTableNumber())) {
                log.warn("批量新增预订服务桌号失败：桌号不能为空");
                throw new RuntimeException("桌号不能为空");
            }
            if (table.getSeatingCapacity() == null || table.getSeatingCapacity() <= 0) {
                log.warn("批量新增预订服务桌号失败：座位数必须大于0");
                throw new RuntimeException("座位数必须大于0");
            }
            
            // 处理桌号：去除前后空格
            String tableNumber = table.getTableNumber().trim();
            table.setTableNumber(tableNumber);
            table.setStoreId(storeId);
            table.setCategoryId(categoryId);
            table.setCreatedUserId(userId);
        }
        
        // 检查是否有重复的桌号（在本次批量添加的列表中）
        long distinctCount = tables.stream()
                .map(StoreBookingTable::getTableNumber)
                .distinct()
                .count();
        if (distinctCount != tables.size()) {
            log.warn("批量新增预订服务桌号失败：本次批量添加的桌号列表中存在重复");
            throw new RuntimeException("本次批量添加的桌号列表中存在重复");
        }
        
        // 检查同一分类下是否已存在相同的桌号（不同分类可以同名）
        List<String> tableNumbers = tables.stream()
                .map(StoreBookingTable::getTableNumber)
                .collect(Collectors.toList());
        
        LambdaQueryWrapper<StoreBookingTable> checkWrapper = new LambdaQueryWrapper<>();
        checkWrapper.eq(StoreBookingTable::getStoreId, storeId)
                .eq(StoreBookingTable::getCategoryId, categoryId)
                .in(StoreBookingTable::getTableNumber, tableNumbers);
        // @TableLogic 会自动过滤已删除的记录（delete_flag=0）
        List<StoreBookingTable> existingTables = this.list(checkWrapper);
        
        if (!existingTables.isEmpty()) {
            List<String> existingNumbers = existingTables.stream()
                    .map(StoreBookingTable::getTableNumber)
                    .distinct()
                    .collect(Collectors.toList());
            log.warn("批量新增预订服务桌号失败：同一分类下桌号已存在，storeId={}, categoryId={}, existingNumbers={}", 
                    storeId, categoryId, existingNumbers);
            if (existingNumbers.size() == 1) {
                throw new RuntimeException("此桌号已存在");
            } else {
                throw new RuntimeException("此桌号已存在：" + String.join("、", existingNumbers));
            }
        }
        
        // 批量保存
        return this.saveBatch(tables);
    }

    @Override
    public boolean updateTable(StoreBookingTable table) {
        log.info("StoreBookingTableServiceImpl.updateTable?table={}", table);
        
        // 从JWT获取当前登录用户ID
        Integer userId = getCurrentUserId();
        
        // 参数验证
        if (table.getId() == null) {
            log.warn("更新预订服务桌号失败：桌号ID不能为空");
            throw new RuntimeException("桌号ID不能为空");
        }
        
        StoreBookingTable existingTable = this.getById(table.getId());
        if (existingTable == null) {
            log.warn("更新预订服务桌号失败：桌号不存在，id={}", table.getId());
            throw new RuntimeException("桌号不存在");
        }
        
        // 如果修改了桌号，检查新桌号是否已存在
        if (StringUtils.hasText(table.getTableNumber())) {
            // 处理桌号：去除前后空格
            String tableNumber = table.getTableNumber().trim();
            table.setTableNumber(tableNumber);
            
            // 如果桌号有变化，检查同一分类下是否已存在相同的桌号（不同分类可以同名，排除当前记录）
            if (!tableNumber.equals(existingTable.getTableNumber())) {
                // 如果分类ID也变化了，使用新的分类ID；否则使用原有的分类ID
                Integer checkCategoryId = table.getCategoryId() != null ? table.getCategoryId() : existingTable.getCategoryId();
                
                LambdaQueryWrapper<StoreBookingTable> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(StoreBookingTable::getStoreId, existingTable.getStoreId())
                        .eq(StoreBookingTable::getCategoryId, checkCategoryId)
                        .eq(StoreBookingTable::getTableNumber, tableNumber)
                        .ne(StoreBookingTable::getId, table.getId());
                // @TableLogic 会自动过滤已删除的记录（delete_flag=0）
                StoreBookingTable duplicateTable = this.getOne(wrapper);
                if (duplicateTable != null) {
                    log.warn("更新预订服务桌号失败：同一分类下桌号已存在，storeId={}, categoryId={}, tableNumber={}, id={}", 
                            existingTable.getStoreId(), checkCategoryId, tableNumber, table.getId());
                    throw new RuntimeException("该分类下桌号已存在不能编辑");
                }
            }
        }
        
        // 验证座位数
        if (table.getSeatingCapacity() != null && table.getSeatingCapacity() <= 0) {
            log.warn("更新预订服务桌号失败：座位数必须大于0");
            throw new RuntimeException("座位数必须大于0");
        }
        
        // 更新字段
        LambdaUpdateWrapper<StoreBookingTable> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(StoreBookingTable::getId, table.getId());
        
        if (StringUtils.hasText(table.getTableNumber())) {
            updateWrapper.set(StoreBookingTable::getTableNumber, table.getTableNumber());
        }
        if (table.getCategoryId() != null) {
            updateWrapper.set(StoreBookingTable::getCategoryId, table.getCategoryId());
        }
        if (table.getSeatingCapacity() != null) {
            updateWrapper.set(StoreBookingTable::getSeatingCapacity, table.getSeatingCapacity());
        }
        
        if (userId != null) {
            updateWrapper.set(StoreBookingTable::getUpdatedUserId, userId);
        }
        
        return this.update(updateWrapper);
    }

    @Override
    public boolean deleteTable(Integer id) {
        log.info("StoreBookingTableServiceImpl.deleteTable?id={}", id);
        
        StoreBookingTable table = this.getById(id);
        if (table == null) {
            log.warn("删除预订服务桌号失败：桌号不存在，id={}", id);
            throw new RuntimeException("桌号不存在");
        }
        
        // 逻辑删除
        return this.removeById(id);
    }

    @Override
    public boolean hasReservationInTable(Integer tableId, Integer storeId) {
        log.info("StoreBookingTableServiceImpl.hasReservationInTable?tableId={}, storeId={}", tableId, storeId);
        
        if (tableId == null || storeId == null) {
            log.warn("查询桌号下是否有预订信息失败：桌号ID或门店ID不能为空");
            return false;
        }
        
        // 查询该桌号下是否有符合条件的预订信息
        // 条件：订单状态为"待使用"(1)或"已完成"(2)
        // 对于"已完成"状态的订单，结束时间需要在当前时间3小时内
        long count = userReservationMapper.countReservationsByTableAndOrderStatus(tableId, storeId);
        boolean hasReservation = count > 0;
        
        log.info("查询桌号下是否有预订信息完成，tableId={}, storeId={}, count={}, hasReservation={}", 
                tableId, storeId, count, hasReservation);
        
        return hasReservation;
    }

    /**
     * 从JWT获取当前登录用户ID
     *
     * @return 用户ID，如果未登录返回null
     */
    private Integer getCurrentUserId() {
        try {
            JSONObject userInfo = JwtUtil.getCurrentUserInfo();
            if (userInfo != null) {
                return userInfo.getInteger("userId");
            }
        } catch (Exception e) {
            log.warn("获取当前登录用户ID失败: {}", e.getMessage());
        }
        return null;
    }
}
