package cn.nianxx.thhotel.platform.identity.repository;

import cn.nianxx.thhotel.platform.common.dto.PlatformPageSnapshot;
import cn.nianxx.thhotel.platform.identity.common.enums.PlatformUserStatus;
import cn.nianxx.thhotel.platform.identity.common.enums.PlatformUserSessionStatus;
import cn.nianxx.thhotel.platform.identity.domain.PlatformUserEntity;
import cn.nianxx.thhotel.platform.identity.domain.PlatformUserSessionEntity;
import cn.nianxx.thhotel.platform.identity.mapper.PlatformUserMapper;
import cn.nianxx.thhotel.platform.identity.mapper.PlatformUserSessionMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Optional;
import org.springframework.stereotype.Repository;

/**
 * 基于 MyBatis-Plus 的平台用户与 session 仓储实现。
 */
@Repository
public class MybatisPlatformIdentityRepository implements PlatformIdentityRepository {

    private final PlatformUserMapper userMapper;
    private final PlatformUserSessionMapper sessionMapper;

    public MybatisPlatformIdentityRepository(
            PlatformUserMapper userMapper,
            PlatformUserSessionMapper sessionMapper) {
        this.userMapper = userMapper;
        this.sessionMapper = sessionMapper;
    }

    @Override
    public Optional<PlatformUserEntity> findUserByUsername(String username) {
        return Optional.ofNullable(userMapper.selectOne(Wrappers.<PlatformUserEntity>lambdaQuery()
                .eq(PlatformUserEntity::getUsername, username)
                .last("LIMIT 1")));
    }

    @Override
    public Optional<PlatformUserEntity> findUserById(Long userId) {
        if (userId == null) {
            return Optional.empty();
        }
        return Optional.ofNullable(userMapper.selectById(userId));
    }

    @Override
    public PlatformPageSnapshot<PlatformUserEntity> queryUsers(String keyword, String userStatus, int pageNum, int pageSize) {
        Page<PlatformUserEntity> page = userMapper.selectPage(Page.of(pageNum, pageSize),
                Wrappers.<PlatformUserEntity>lambdaQuery()
                        .eq(userStatus != null && !userStatus.isBlank(), PlatformUserEntity::getUserStatus, userStatus)
                        .and(keyword != null && !keyword.isBlank(), wrapper -> wrapper
                                .like(PlatformUserEntity::getUsername, keyword)
                                .or()
                                .like(PlatformUserEntity::getDisplayName, keyword)
                                .or()
                                .like(PlatformUserEntity::getEmail, keyword)
                                .or()
                                .like(PlatformUserEntity::getPhone, keyword))
                        .orderByAsc(PlatformUserEntity::getUsername));
        return new PlatformPageSnapshot<>(page.getRecords(), page.getTotal(), pageNum, pageSize);
    }

    @Override
    public long countSuperAdminUsers() {
        return userMapper.selectCount(Wrappers.<PlatformUserEntity>lambdaQuery()
                .eq(PlatformUserEntity::getSuperAdmin, true)
                .eq(PlatformUserEntity::getUserStatus, PlatformUserStatus.ACTIVE.name()));
    }

    @Override
    public void insertUser(PlatformUserEntity user) {
        userMapper.insert(user);
    }

    @Override
    public void updateUser(PlatformUserEntity user) {
        userMapper.updateById(user);
    }

    @Override
    public void insertSession(PlatformUserSessionEntity session) {
        sessionMapper.insert(session);
    }

    @Override
    public Optional<PlatformUserSessionEntity> findSessionByTokenHash(String tokenHash) {
        return Optional.ofNullable(sessionMapper.selectOne(Wrappers.<PlatformUserSessionEntity>lambdaQuery()
                .eq(PlatformUserSessionEntity::getTokenHash, tokenHash)
                .last("LIMIT 1")));
    }

    @Override
    public void updateSession(PlatformUserSessionEntity session) {
        sessionMapper.updateById(session);
    }

    @Override
    public void revokeActiveSessionsByUserId(Long userId) {
        if (userId == null) {
            return;
        }
        LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC);
        PlatformUserSessionEntity update = new PlatformUserSessionEntity();
        update.setSessionStatus(PlatformUserSessionStatus.REVOKED.name());
        update.setRevokedAt(now);
        update.setUpdatedAt(now);
        sessionMapper.update(update, Wrappers.<PlatformUserSessionEntity>lambdaUpdate()
                .eq(PlatformUserSessionEntity::getUserId, userId)
                .eq(PlatformUserSessionEntity::getSessionStatus, PlatformUserSessionStatus.ACTIVE.name()));
    }
}
