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

import cn.nianxx.thhotel.platform.hotel.domain.PlatformHotelEntity;
import cn.nianxx.thhotel.platform.hotel.service.HotelContextException;
import cn.nianxx.thhotel.platform.hotel.repository.PlatformHotelRepository;
import cn.nianxx.thhotel.platform.hotel.service.HotelContextService;
import cn.nianxx.thhotel.platform.security.common.dto.AuthenticatedUserContext;
import cn.nianxx.thhotel.platform.security.service.CurrentUserContextService;
import java.util.List;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;

/**
 * 酒店上下文解析服务实现。单酒店阶段以平台酒店表唯一 ACTIVE 酒店作为系统酒店事实来源。
 */
@Service
public class HotelContextServiceImpl implements HotelContextService {

    private final PlatformHotelRepository hotelRepository;
    private final CurrentUserContextService currentUserContextService;

    /**
     * 注入平台酒店仓储和当前用户上下文服务，避免业务模块各自读取配置兜底酒店。
     */
    public HotelContextServiceImpl(
            PlatformHotelRepository hotelRepository,
            CurrentUserContextService currentUserContextService) {
        this.hotelRepository = hotelRepository;
        this.currentUserContextService = currentUserContextService;
    }

    /**
     * 解析系统酒店。单酒店阶段严格要求平台酒店表只有一家 ACTIVE 酒店。
     */
    @Override
    public String resolveSystemHotelId() {
        List<PlatformHotelEntity> activeHotels = hotelRepository.listActiveHotels();
        if (activeHotels == null || activeHotels.isEmpty()) {
            throw new HotelContextException(
                    HttpStatus.CONFLICT,
                    "SYSTEM_HOTEL_NOT_CONFIGURED",
                    "系统酒店未配置，请先在平台酒店表配置一家 ACTIVE 酒店。");
        }
        if (activeHotels.size() > 1) {
            throw new HotelContextException(
                    HttpStatus.CONFLICT,
                    "SYSTEM_HOTEL_AMBIGUOUS",
                    "单酒店阶段只允许平台酒店表存在一家 ACTIVE 酒店。");
        }
        String hotelId = trimToNull(activeHotels.get(0).getHotelId());
        if (hotelId == null) {
            throw new HotelContextException(
                    HttpStatus.CONFLICT,
                    "SYSTEM_HOTEL_NOT_CONFIGURED",
                    "系统酒店 ID 为空，请检查平台酒店表。");
        }
        return hotelId;
    }

    /**
     * 解析当前请求酒店。登录用户按授权酒店校验；未登录兼容入口按系统酒店解析并严格比对显式请求值。
     */
    @Override
    public String resolveCurrentHotelId(String requestedHotelId) {
        String normalizedRequestedHotelId = trimToNull(requestedHotelId);
        return currentUserContextService.currentUser()
                .map(context -> resolveUserHotelId(context, normalizedRequestedHotelId))
                .orElseGet(() -> resolveAnonymousHotelId(normalizedRequestedHotelId));
    }

    /**
     * 要求当前请求可访问指定酒店。空入参走当前酒店解析，非空入参走授权校验。
     */
    @Override
    public String requireAccessibleHotel(String hotelId) {
        return resolveCurrentHotelId(hotelId);
    }

    /**
     * 已登录用户酒店解析。显式请求酒店必须在可访问列表内，缺省时使用默认酒店。
     */
    private String resolveUserHotelId(AuthenticatedUserContext context, String requestedHotelId) {
        List<String> accessibleHotelIds = context.accessibleHotelIds() == null
                ? List.of()
                : context.accessibleHotelIds();
        if (requestedHotelId != null) {
            if (accessibleHotelIds.contains(requestedHotelId)) {
                return requestedHotelId;
            }
            throw accessDenied();
        }
        String defaultHotelId = trimToNull(context.defaultHotelId());
        if (defaultHotelId != null && accessibleHotelIds.contains(defaultHotelId)) {
            return defaultHotelId;
        }
        return accessibleHotelIds.stream()
                .filter(this::hasText)
                .findFirst()
                .orElseThrow(this::accessDenied);
    }

    /**
     * 未登录兼容入口酒店解析。请求未传酒店时使用系统酒店，显式酒店必须等于系统酒店。
     */
    private String resolveAnonymousHotelId(String requestedHotelId) {
        String systemHotelId = resolveSystemHotelId();
        if (requestedHotelId == null || systemHotelId.equals(requestedHotelId)) {
            return systemHotelId;
        }
        throw accessDenied();
    }

    /**
     * 构造酒店访问拒绝异常，不回显用户或酒店授权细节。
     */
    private HotelContextException accessDenied() {
        return new HotelContextException(
                HttpStatus.FORBIDDEN,
                "HOTEL_ACCESS_DENIED",
                "当前用户无权访问该酒店。");
    }

    private boolean hasText(String value) {
        return trimToNull(value) != null;
    }

    private String trimToNull(String value) {
        if (value == null || value.trim().isEmpty()) {
            return null;
        }
        return value.trim();
    }
}
