package cn.nianxx.thhotel.platform.hotel.service.impl;

import cn.nianxx.thhotel.platform.hotel.domain.PlatformHotelEntity;
import cn.nianxx.thhotel.platform.hotel.repository.PlatformHotelRepository;
import cn.nianxx.thhotel.platform.hotel.service.HotelAccessService;
import cn.nianxx.thhotel.platform.identity.common.result.AuthHotelResult;
import cn.nianxx.thhotel.platform.identity.domain.PlatformUserEntity;
import cn.nianxx.thhotel.platform.identity.service.impl.AuthProperties;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.springframework.stereotype.Service;

/**
 * 平台酒店授权服务实现。超级管理员可访问全部启用酒店，普通用户只访问授权酒店。
 */
@Service
public class HotelAccessServiceImpl implements HotelAccessService {

    private final PlatformHotelRepository hotelRepository;
    private final AuthProperties authProperties;

    /**
     * 注入酒店仓储和登录配置，用于解析当前用户酒店上下文。
     */
    public HotelAccessServiceImpl(
            PlatformHotelRepository hotelRepository,
            AuthProperties authProperties) {
        this.hotelRepository = hotelRepository;
        this.authProperties = authProperties;
    }

    /**
     * 查询当前用户可访问酒店，并根据前端偏好、用户默认酒店和系统默认酒店标记默认项。
     */
    @Override
    public List<AuthHotelResult> listAccessibleHotels(PlatformUserEntity user, String preferredHotelId) {
        List<PlatformHotelEntity> activeHotels = hotelRepository.listActiveHotels();
        Set<String> accessibleHotelIds = resolveAccessibleHotelIds(user, activeHotels);
        String defaultHotelId = resolveDefaultHotelId(user, accessibleHotelIds, preferredHotelId);
        return activeHotels.stream()
                .filter(hotel -> accessibleHotelIds.contains(hotel.getHotelId()))
                .map(hotel -> new AuthHotelResult(
                        hotel.getHotelId(),
                        hotel.getHotelName(),
                        hotel.getTimeZone(),
                        hotel.getHotelId().equals(defaultHotelId)))
                .toList();
    }

    /**
     * 判断当前用户是否可访问指定酒店。空酒店 ID 第一版视为不可访问。
     */
    @Override
    public boolean canAccessHotel(PlatformUserEntity user, String hotelId) {
        if (user == null || hotelId == null || hotelId.isBlank()) {
            return false;
        }
        return resolveAccessibleHotelIds(user, hotelRepository.listActiveHotels()).contains(hotelId);
    }

    /**
     * 从酒店响应列表中解析默认酒店 ID；没有显式默认时返回第一家可访问酒店。
     */
    @Override
    public String resolveDefaultHotelId(List<AuthHotelResult> hotels) {
        return hotels.stream()
                .filter(hotel -> Boolean.TRUE.equals(hotel.defaultHotel()))
                .map(AuthHotelResult::hotelId)
                .findFirst()
                .orElseGet(() -> hotels.isEmpty() ? null : hotels.get(0).hotelId());
    }

    /**
     * 解析当前用户可访问酒店；超级管理员取全部启用酒店，普通用户取授权关系。
     */
    private Set<String> resolveAccessibleHotelIds(PlatformUserEntity user, List<PlatformHotelEntity> activeHotels) {
        if (Boolean.TRUE.equals(user.getSuperAdmin())) {
            return new LinkedHashSet<>(activeHotels.stream()
                    .map(PlatformHotelEntity::getHotelId)
                    .toList());
        }
        return new LinkedHashSet<>(hotelRepository.listUserHotelIds(user.getId()));
    }

    /**
     * 按前端偏好、用户默认酒店、系统默认酒店的优先级解析当前默认酒店。
     */
    private String resolveDefaultHotelId(
            PlatformUserEntity user,
            Set<String> accessibleHotelIds,
            String preferredHotelId) {
        if (preferredHotelId != null && accessibleHotelIds.contains(preferredHotelId)) {
            return preferredHotelId;
        }
        if (!Boolean.TRUE.equals(user.getSuperAdmin())) {
            String userDefaultHotelId = hotelRepository.findUserDefaultHotelId(user.getId()).orElse(null);
            if (userDefaultHotelId != null && accessibleHotelIds.contains(userDefaultHotelId)) {
                return userDefaultHotelId;
            }
        }
        String configuredDefaultHotelId = authProperties.getBootstrap().getDefaultHotelId();
        if (configuredDefaultHotelId != null && accessibleHotelIds.contains(configuredDefaultHotelId)) {
            return configuredDefaultHotelId;
        }
        return accessibleHotelIds.stream().findFirst().orElse(null);
    }
}
