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 shop.alien.entity.store.StoreBookingCategory;
import shop.alien.entity.store.StoreBookingSettings;
import shop.alien.entity.store.StoreBookingTable;
import shop.alien.entity.store.UserReservation;
import shop.alien.mapper.StoreBookingCategoryMapper;
import shop.alien.mapper.UserReservationMapper;
import shop.alien.store.service.StoreBookingCategoryService;
import shop.alien.store.service.StoreBookingSettingsService;
import shop.alien.store.service.StoreBookingTableService;
import shop.alien.util.common.JwtUtil;

import java.util.List;

/**
 * 预订服务分类表 服务实现类
 *
 * @author system
 * @since 2025-01-XX
 */
@Slf4j
@Service
@Transactional
public class StoreBookingCategoryServiceImpl extends ServiceImpl<StoreBookingCategoryMapper, StoreBookingCategory> implements StoreBookingCategoryService {

    private final StoreBookingTableService storeBookingTableService;
    private final UserReservationMapper userReservationMapper;
    private final StoreBookingSettingsService storeBookingSettingsService;

    public StoreBookingCategoryServiceImpl(
            StoreBookingTableService storeBookingTableService,
            UserReservationMapper userReservationMapper,
            @Lazy StoreBookingSettingsService storeBookingSettingsService) {
        this.storeBookingTableService = storeBookingTableService;
        this.userReservationMapper = userReservationMapper;
        this.storeBookingSettingsService = storeBookingSettingsService;
    }

    @Override
    public List<StoreBookingCategory> getCategoryList(Integer storeId) {
        log.info("StoreBookingCategoryServiceImpl.getCategoryList?storeId={}", storeId);
        
        LambdaQueryWrapper<StoreBookingCategory> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreBookingCategory::getStoreId, storeId)
                .orderByAsc(StoreBookingCategory::getSort) // 按排序字段升序
                .orderByDesc(StoreBookingCategory::getCreatedTime); // 如果排序字段相同，按创建时间倒序
        
        return this.list(wrapper);
    }

    @Override
    public IPage<StoreBookingCategory> getCategoryListPage(Integer pageNum, Integer pageSize, Integer storeId) {
        log.info("StoreBookingCategoryServiceImpl.getCategoryListPage?pageNum={}, pageSize={}, storeId={}", 
                pageNum, pageSize, storeId);
        
        // 构建分页对象
        Page<StoreBookingCategory> page = new Page<>(pageNum, pageSize);
        
        // 构建查询条件
        LambdaQueryWrapper<StoreBookingCategory> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreBookingCategory::getStoreId, storeId)
                .orderByAsc(StoreBookingCategory::getSort) // 按排序字段升序
                .orderByDesc(StoreBookingCategory::getCreatedTime); // 如果排序字段相同，按创建时间倒序
        
        // 执行分页查询
        return this.page(page, wrapper);
    }

    @Override
    public boolean addCategory(StoreBookingCategory category) {
        log.info("StoreBookingCategoryServiceImpl.addCategory?category={}", category);
        
        // 从JWT获取当前登录用户ID
        Integer userId = getCurrentUserId();
        
        // 参数验证
        if (category.getStoreId() == null) {
            log.warn("新增预订服务分类失败：门店ID不能为空");
            throw new RuntimeException("门店ID不能为空");
        }
        if (!StringUtils.hasText(category.getCategoryName())) {
            log.warn("新增预订服务分类失败：分类名称不能为空");
            throw new RuntimeException("分类名称不能为空");
        }
        if (!StringUtils.hasText(category.getFloorPlanImages())) {
            log.warn("新增预订服务分类失败：平面图不能为空");
            throw new RuntimeException("平面图不能为空");
        }
        if (category.getMaxBookingTime() == null || category.getMaxBookingTime() <= 0) {
            log.warn("新增预订服务分类失败：最长预订时间必须大于0");
            throw new RuntimeException("最长预订时间必须大于0");
        }
        
        // 校验：如果当前门店有信息设置，分类中的最长预订时间要超过信息设置的保留时间
        // 如果没有信息设置，分类的最长预订时间可随意设置
        StoreBookingSettings settings = storeBookingSettingsService.getByStoreId(category.getStoreId());
        if (settings != null) {
            // 如果门店有信息设置，且设置了保留位置（retain_position_flag = 1）
            if (settings.getRetainPositionFlag() != null && settings.getRetainPositionFlag() == 1) {
                // 如果设置了保留时长，则分类的最长预订时间要超过保留时长
                if (settings.getRetentionDuration() != null && settings.getRetentionDuration() > 0) {
                    if (category.getMaxBookingTime() <= settings.getRetentionDuration()) {
                        log.warn("新增预订服务分类失败：分类的最长预订时间要超过信息设置的保留时间，maxBookingTime={}, retentionDuration={}", 
                                category.getMaxBookingTime(), settings.getRetentionDuration());
                        throw new RuntimeException("分类的最长预订时间要超过信息设置的保留时间（" + settings.getRetentionDuration() + "分钟）");
                    }
                }
            }
        }
        
        // 验证图片数量（最多9张）
        String[] images = category.getFloorPlanImages().split(",");
        if (images.length > 9) {
            log.warn("新增预订服务分类失败：平面图最多9张");
            throw new RuntimeException("平面图最多9张");
        }
        
        // 先通过门店ID查询当前门店下的所有分类，检查分类名称是否重复
        // 处理分类名称：去除前后空格
        String categoryName = category.getCategoryName().trim();
        category.setCategoryName(categoryName);
        
        // 查询当前门店下是否已存在相同的分类名称（只检查未删除的记录）
        LambdaQueryWrapper<StoreBookingCategory> checkWrapper = new LambdaQueryWrapper<>();
        checkWrapper.eq(StoreBookingCategory::getStoreId, category.getStoreId())
                .eq(StoreBookingCategory::getCategoryName, categoryName);
        // @TableLogic 会自动过滤已删除的记录（delete_flag=0）
        StoreBookingCategory existingCategory = this.getOne(checkWrapper);
        if (existingCategory != null) {
            log.warn("新增预订服务分类失败：当前门店下分类名称已存在，storeId={}, categoryName={}", 
                    category.getStoreId(), categoryName);
            throw new RuntimeException("此名称已存在");
        }
        
        // 查询当前最大的排序值
        LambdaQueryWrapper<StoreBookingCategory> maxSortWrapper = new LambdaQueryWrapper<>();
        maxSortWrapper.eq(StoreBookingCategory::getStoreId, category.getStoreId())
                .orderByDesc(StoreBookingCategory::getSort)
                .last("LIMIT 1");
        StoreBookingCategory maxSortCategory = this.getOne(maxSortWrapper);
        int maxSort = (maxSortCategory != null && maxSortCategory.getSort() != null) ? maxSortCategory.getSort() : 0;
        
        // 设置默认值
        if (category.getIsDisplay() == null) {
            category.setIsDisplay(1); // 默认显示
        }
        if (category.getSort() == null) {
            category.setSort(maxSort + 1); // 设置排序值
        }
        category.setCreatedUserId(userId);
        
        return this.save(category);
    }

    @Override
    public boolean updateCategory(StoreBookingCategory category) {
        log.info("StoreBookingCategoryServiceImpl.updateCategory?category={}", category);
        
        // 从JWT获取当前登录用户ID
        Integer userId = getCurrentUserId();
        
        // 参数验证
        if (category.getId() == null) {
            log.warn("更新预订服务分类失败：分类ID不能为空");
            throw new RuntimeException("分类ID不能为空");
        }
        
        StoreBookingCategory existingCategory = this.getById(category.getId());
        if (existingCategory == null) {
            log.warn("更新预订服务分类失败：分类不存在，id={}", category.getId());
            throw new RuntimeException("分类不存在");
        }
        
        // 如果修改了分类名称，先通过门店ID查询当前门店下的所有分类，检查新分类名称是否重复
        if (StringUtils.hasText(category.getCategoryName())) {
            // 处理分类名称：去除前后空格
            String categoryName = category.getCategoryName().trim();
            category.setCategoryName(categoryName);
            
            // 如果分类名称有变化，检查当前门店下是否已存在相同的分类名称
            if (!categoryName.equals(existingCategory.getCategoryName())) {
                // 查询当前门店下是否已存在相同的分类名称（排除当前记录，只检查未删除的记录）
                LambdaQueryWrapper<StoreBookingCategory> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(StoreBookingCategory::getStoreId, existingCategory.getStoreId())
                        .eq(StoreBookingCategory::getCategoryName, categoryName)
                        .ne(StoreBookingCategory::getId, category.getId());
                // @TableLogic 会自动过滤已删除的记录（delete_flag=0）
                StoreBookingCategory duplicateCategory = this.getOne(wrapper);
                if (duplicateCategory != null) {
                    log.warn("更新预订服务分类失败：当前门店下分类名称已存在，storeId={}, categoryName={}, id={}", 
                            existingCategory.getStoreId(), categoryName, category.getId());
                    throw new RuntimeException("此名称已存在");
                }
            }
        }
        
        // 验证图片数量（最多9张）
        if (StringUtils.hasText(category.getFloorPlanImages())) {
            String[] images = category.getFloorPlanImages().split(",");
            if (images.length > 9) {
                log.warn("更新预订服务分类失败：平面图最多9张");
                throw new RuntimeException("平面图最多9张");
            }
        }
        
        // 验证最长预订时间
        if (category.getMaxBookingTime() != null && category.getMaxBookingTime() <= 0) {
            log.warn("更新预订服务分类失败：最长预订时间必须大于0");
            throw new RuntimeException("最长预订时间必须大于0");
        }
        
        // 更新字段
        LambdaUpdateWrapper<StoreBookingCategory> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(StoreBookingCategory::getId, category.getId());
        
        if (StringUtils.hasText(category.getCategoryName())) {
            updateWrapper.set(StoreBookingCategory::getCategoryName, category.getCategoryName());
        }
        if (StringUtils.hasText(category.getFloorPlanImages())) {
            updateWrapper.set(StoreBookingCategory::getFloorPlanImages, category.getFloorPlanImages());
        }
        if (category.getIsDisplay() != null) {
            updateWrapper.set(StoreBookingCategory::getIsDisplay, category.getIsDisplay());
        }
        if (category.getMaxBookingTime() != null) {
            updateWrapper.set(StoreBookingCategory::getMaxBookingTime, category.getMaxBookingTime());
        }
        if (category.getSort() != null) {
            updateWrapper.set(StoreBookingCategory::getSort, category.getSort());
        }
        
        if (userId != null) {
            updateWrapper.set(StoreBookingCategory::getUpdatedUserId, userId);
        }
        
        return this.update(updateWrapper);
    }

    @Override
    public boolean deleteCategory(Integer id) {
        log.info("StoreBookingCategoryServiceImpl.deleteCategory?id={}", id);
        
        StoreBookingCategory category = this.getById(id);
        if (category == null) {
            log.warn("删除预订服务分类失败：分类不存在，id={}", id);
            throw new RuntimeException("分类不存在");
        }
        
        // 查询当前分类下的所有桌号
        LambdaQueryWrapper<StoreBookingTable> tableWrapper = new LambdaQueryWrapper<>();
        tableWrapper.eq(StoreBookingTable::getCategoryId, id);
        // @TableLogic 会自动过滤已删除的记录（delete_flag=0）
        List<StoreBookingTable> tables = storeBookingTableService.list(tableWrapper);
        
        // 如果存在桌号，先批量删除这些桌号
        if (tables != null && !tables.isEmpty()) {
            List<Integer> tableIds = tables.stream()
                    .map(StoreBookingTable::getId)
                    .collect(java.util.stream.Collectors.toList());
            
            log.info("删除分类时同时删除该分类下的所有桌号，categoryId={}, tableCount={}, tableIds={}", 
                    id, tables.size(), tableIds);
            
            // 批量逻辑删除桌号
            boolean deleteTablesResult = storeBookingTableService.removeByIds(tableIds);
            if (!deleteTablesResult) {
                log.warn("删除分类下的桌号失败，categoryId={}, tableIds={}", id, tableIds);
                throw new RuntimeException("删除分类下的桌号失败");
            }
            
            log.info("成功删除分类下的所有桌号，categoryId={}, tableCount={}", id, tables.size());
        }
        
        // 逻辑删除分类
        return this.removeById(id);
    }

    @Override
    public boolean updateCategorySort(Integer storeId, List<Integer> categoryIds) {
        log.info("StoreBookingCategoryServiceImpl.updateCategorySort?storeId={}&categoryIds={}", storeId, categoryIds);
        
        if (storeId == null || categoryIds == null || categoryIds.isEmpty()) {
            log.warn("更新预订服务分类排序失败：参数不完整");
            throw new RuntimeException("参数不完整");
        }
        
        // 验证所有分类ID是否属于该门店
        LambdaQueryWrapper<StoreBookingCategory> checkWrapper = new LambdaQueryWrapper<>();
        checkWrapper.eq(StoreBookingCategory::getStoreId, storeId)
                .in(StoreBookingCategory::getId, categoryIds);
        long count = this.count(checkWrapper);
        if (count != categoryIds.size()) {
            log.warn("更新预订服务分类排序失败：部分分类ID不属于该门店");
            throw new RuntimeException("部分分类ID不属于该门店");
        }
        
        // 从JWT获取当前登录用户ID
        Integer userId = getCurrentUserId();
        
        // 批量更新排序值
        for (int i = 0; i < categoryIds.size(); i++) {
            LambdaUpdateWrapper<StoreBookingCategory> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(StoreBookingCategory::getId, categoryIds.get(i))
                    .set(StoreBookingCategory::getSort, i + 1);
            if (userId != null) {
                updateWrapper.set(StoreBookingCategory::getUpdatedUserId, userId);
            }
            this.update(updateWrapper);
        }
        
        return true;
    }

    @Override
    public boolean updateDisplayStatus(Integer id, Integer isDisplay) {
        log.info("StoreBookingCategoryServiceImpl.updateDisplayStatus?id={}&isDisplay={}", id, isDisplay);
        
        if (id == null) {
            log.warn("更新预订服务分类显示状态失败：分类ID不能为空");
            throw new RuntimeException("分类ID不能为空");
        }
        
        if (isDisplay == null || (isDisplay != 0 && isDisplay != 1)) {
            log.warn("更新预订服务分类显示状态失败：显示状态值无效，isDisplay={}", isDisplay);
            throw new RuntimeException("显示状态值无效，必须为0（隐藏）或1（显示）");
        }
        
        StoreBookingCategory category = this.getById(id);
        if (category == null) {
            log.warn("更新预订服务分类显示状态失败：分类不存在，id={}", id);
            throw new RuntimeException("分类不存在");
        }
        
        // 从JWT获取当前登录用户ID
        Integer userId = getCurrentUserId();
        
        // 更新显示状态
        LambdaUpdateWrapper<StoreBookingCategory> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(StoreBookingCategory::getId, id)
                .set(StoreBookingCategory::getIsDisplay, isDisplay);
        
        if (userId != null) {
            updateWrapper.set(StoreBookingCategory::getUpdatedUserId, userId);
        }
        
        return this.update(updateWrapper);
    }

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