# UserApplicationService.java

    package com.yumu.noveltranslator.application.service;

    import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
    import com.yumu.noveltranslator.config.tenant.TenantContext;
    import com.yumu.noveltranslator.port.dto.entity.TranslationHistoryResponse;
    import com.yumu.noveltranslator.port.dto.entity.UserStatisticsResponse;
    import com.yumu.noveltranslator.port.dto.entity.UserQuotaResponse;
    import com.yumu.noveltranslator.port.dto.entity.UserPreferencesResponse;
    import com.yumu.noveltranslator.port.dto.entity.UserPreferencesRequest;
    import com.yumu.noveltranslator.port.dto.entity.PlatformStatsResponse;
    import com.yumu.noveltranslator.port.dto.translation.GlossaryResponse;
    import com.yumu.noveltranslator.port.dto.translation.GlossaryItemRequest;
    import com.yumu.noveltranslator.port.dto.common.PageResponse;
    import com.yumu.noveltranslator.domain.model.Glossary;
    import com.yumu.noveltranslator.domain.model.User;
    import com.yumu.noveltranslator.domain.model.UserPreference;
    import com.yumu.noveltranslator.enums.ErrorCodeEnum;
    import com.yumu.noveltranslator.port.out.GlossaryRepositoryPort;
    import com.yumu.noveltranslator.port.out.TranslationRepositoryPort;
    import com.yumu.noveltranslator.port.out.UserRepositoryPort;
    import com.yumu.noveltranslator.properties.TranslationLimitProperties;
    import com.yumu.noveltranslator.domain.service.QuotaService;
    import lombok.RequiredArgsConstructor;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.time.LocalDate;
    import java.time.LocalDateTime;
    import java.util.List;
    import java.util.stream.Collectors;

    /**
     * 用户信息服务：个人资料、术语库、偏好设置、统计数据
     */
    @Service
    @RequiredArgsConstructor
    public class UserApplicationService implements com.yumu.noveltranslator.port.in.UserPort {

        private final UserRepositoryPort userPort;
        private final TranslationRepositoryPort translationPort;
        private final GlossaryRepositoryPort glossaryPort;
        private final TranslationLimitProperties limitProperties;
        private final QuotaService quotaService;
        private final com.yumu.noveltranslator.port.in.TranslationTaskPort translationTaskPort;

        /**
         * 更新用户信息
         */
        public void updateUser(User user) {
            userPort.update(user);
        }

        /**
         * 获取用户统计数据
         */
        public UserStatisticsResponse getUserStatistics(Long userId) {
            UserStatisticsResponse response = new UserStatisticsResponse();

            int totalCount = translationPort.countHistoryByUserId(userId);
            response.setTotalTranslations(totalCount);

            int textCount = translationPort.countHistoryByUserIdAndType(userId, "text");
            int docCount = translationPort.countHistoryByUserIdAndType(userId, "document");
            response.setTextTranslations(textCount);
            response.setDocumentTranslations(docCount);

            Long totalChars = translationPort.sumHistorySourceTextLengthByUserId(userId);
            response.setTotalCharacters(totalChars != null ? totalChars : 0L);
            response.setTotalDocuments(docCount);

            LocalDateTime weekAgo = LocalDateTime.now().minusWeeks(1);
            LocalDateTime monthAgo = LocalDateTime.now().minusMonths(1);
            response.setWeekTranslations(translationPort.countHistoryByUserIdAfter(userId, weekAgo));
            response.setMonthTranslations(translationPort.countHistoryByUserIdAfter(userId, monthAgo));

            return response;
        }

        /**
         * 获取用户配额信息
         */
        public UserQuotaResponse getUserQuota(User user) {
            UserQuotaResponse response = new UserQuotaResponse();
            String level = user.getUserLevel() != null ? user.getUserLevel() : "free";
            response.setUserLevel(level.toUpperCase());

            long monthlyChars = quotaService.getMonthlyQuota(level);
            long usedThisMonth = quotaService.getUsedThisMonth(user.getId());
            long remaining = Math.max(0, monthlyChars - usedThisMonth);

            response.setMonthlyChars(monthlyChars);
            response.setUsedThisMonth(usedThisMonth);
            response.setRemainingChars(remaining);

            int concurrency;
            if ("max".equalsIgnoreCase(level)) {
                concurrency = limitProperties.getMaxConcurrencyLimit();
            } else if ("pro".equalsIgnoreCase(level)) {
                concurrency = limitProperties.getProConcurrencyLimit();
            } else {
                concurrency = limitProperties.getFreeConcurrencyLimit();
            }
            response.setConcurrencyLimit(concurrency);

            double fastMult = limitProperties.getFastModeMultiplier();
            double expertMult = limitProperties.getExpertModeMultiplier();
            double teamMult = limitProperties.getTeamModeMultiplier();
            response.setFastModeEquivalent((long) (remaining / fastMult));
            response.setExpertModeEquivalent((long) (remaining / expertMult));
            response.setTeamModeEquivalent((long) (remaining / teamMult));

            return response;
        }

        /**
         * 获取术语库列表
         */
        public PageResponse<GlossaryResponse> getGlossaryList(Long userId, int page, int pageSize, String search) {
            var glossaryPage = glossaryPort.findGlossaryPaged(userId, search, page, pageSize);

            List<GlossaryResponse> list = glossaryPage.getRecords().stream()
                    .map(this::toGlossaryResponse)
                    .collect(Collectors.toList());

            return PageResponse.of(page, pageSize, glossaryPage.getTotal(), list);
        }

        /**
         * 获取术语库详情
         */
        public GlossaryResponse getGlossaryDetail(Long userId, Long glossaryId) {
            return glossaryPort.findGlossaryById(glossaryId)
                    .filter(g -> g.getDeleted() == null || g.getDeleted() != 1)
                    .filter(g -> g.getUserId().equals(userId))
                    .map(this::toGlossaryResponse)
                    .orElse(null);
        }

        /**
         * 获取术语列表
         */
        public List<GlossaryResponse> getGlossaryTerms(Long userId) {
            return fetchAllGlossaries(userId);
        }

        private List<GlossaryResponse> fetchAllGlossaries(Long userId) {
            return glossaryPort.findGlossaryByUserId(userId).stream()
                    .map(this::toGlossaryResponse)
                    .collect(Collectors.toList());
        }

        /**
         * 创建术语项
         */
        public GlossaryResponse createGlossaryItem(Long userId, GlossaryItemRequest request) {
            Glossary glossary = new Glossary();
            glossary.setUserId(userId);
            glossary.setSourceWord(request.getSourceWord());
            glossary.setTargetWord(request.getTargetWord());
            glossary.setRemark(request.getRemark());

            glossaryPort.saveGlossary(glossary);
            return toGlossaryResponse(glossary);
        }

        /**
         * 更新术语项
         */
        public GlossaryResponse updateGlossaryItem(Long userId, Long glossaryId, GlossaryItemRequest request) {
            return glossaryPort.findGlossaryById(glossaryId)
                    .filter(g -> g.getDeleted() == null || g.getDeleted() != 1)
                    .filter(g -> g.getUserId().equals(userId))
                    .map(glossary -> {
                        if (request.getSourceWord() != null) {
                            glossary.setSourceWord(request.getSourceWord());
                        }
                        if (request.getTargetWord() != null) {
                            glossary.setTargetWord(request.getTargetWord());
                        }
                        if (request.getRemark() != null) {
                            glossary.setRemark(request.getRemark());
                        }
                        glossaryPort.updateGlossary(glossary);
                        return toGlossaryResponse(glossary);
                    }).orElse(null);
        }

        /**
         * 删除术语项
         */
        public boolean deleteGlossaryItem(Long userId, Long glossaryId) {
            return glossaryPort.findGlossaryById(glossaryId)
                    .filter(g -> g.getDeleted() == null || g.getDeleted() != 1)
                    .filter(g -> g.getUserId().equals(userId))
                    .map(glossaryPort::deleteGlossary)
                    .orElse(false);
        }

        /**
         * 批量导入术语
         */
        public int batchImportGlossaryItems(Long userId, List<GlossaryItemRequest> items) {
            int count = 0;
            for (GlossaryItemRequest item : items) {
                try {
                    createGlossaryItem(userId, item);
                    count++;
                } catch (Exception e) {
                    // 跳过失败的项
                }
            }
            return count;
        }

        /**
         * 获取用户偏好设置
         */
        public UserPreferencesResponse getUserPreferences(Long userId) {
            return userPort.findPreferenceByUserId(userId)
                    .map(this::toPreferencesResponse)
                    .orElseGet(this::buildDefaultPreferences);
        }

        /**
         * 更新用户偏好设置
         */
        public UserPreferencesResponse updateUserPreferences(Long userId, UserPreferencesRequest request) {
            return userPort.findPreferenceByUserId(userId).map(pref -> {
                if (request.getDefaultEngine() != null) pref.setDefaultEngine(request.getDefaultEngine());
                if (request.getDefaultTargetLang() != null) pref.setDefaultTargetLang(request.getDefaultTargetLang());
                if (request.getEnableGlossary() != null) pref.setEnableGlossary(request.getEnableGlossary());
                if (request.getDefaultGlossaryId() != null) pref.setDefaultGlossaryId(request.getDefaultGlossaryId());
                if (request.getEnableCache() != null) pref.setEnableCache(request.getEnableCache());
                if (request.getAutoTranslateSelection() != null) pref.setAutoTranslateSelection(request.getAutoTranslateSelection());
                if (request.getFontSize() != null) pref.setFontSize(request.getFontSize());
                if (request.getThemeMode() != null) pref.setThemeMode(request.getThemeMode());
                userPort.updatePreference(pref);
                return toPreferencesResponse(pref);
            }).orElseGet(() -> {
                UserPreference pref = new UserPreference();
                pref.setUserId(userId);
                pref.setDefaultEngine(request.getDefaultEngine() != null ? request.getDefaultEngine() : "google");
                pref.setDefaultTargetLang(request.getDefaultTargetLang() != null ? request.getDefaultTargetLang() : "zh");
                pref.setEnableGlossary(request.getEnableGlossary() != null ? request.getEnableGlossary() : true);
                pref.setDefaultGlossaryId(request.getDefaultGlossaryId());
                pref.setEnableCache(request.getEnableCache() != null ? request.getEnableCache() : true);
                pref.setAutoTranslateSelection(request.getAutoTranslateSelection() != null ? request.getAutoTranslateSelection() : true);
                pref.setFontSize(request.getFontSize() != null ? request.getFontSize() : 14);
                pref.setThemeMode(request.getThemeMode() != null ? request.getThemeMode() : "light");
                userPort.savePreference(pref);
                return toPreferencesResponse(pref);
            });
        }

        /**
         * 获取平台统计信息（跨租户全局统计）
         */
        public PlatformStatsResponse getPlatformStats() {
            PlatformStatsResponse response = new PlatformStatsResponse();

            try {
                TenantContext.setBypassTenant(true);

                response.setTotalUsers(userPort.countActiveUsers());

                LocalDateTime weekAgo = LocalDateTime.now().minusWeeks(1);
                LocalDateTime monthAgo = LocalDateTime.now().minusMonths(1);
                LocalDateTime todayStart = LocalDate.now().atStartOfDay();
                response.setActiveUsersWeek(translationPort.countActiveUsersAfter(weekAgo));
                response.setActiveUsersMonth(translationPort.countActiveUsersAfter(monthAgo));
                response.setActiveUsersToday(translationPort.countActiveUsersAfter(todayStart));

                response.setTotalTranslations(translationPort.countAllHistory());
                response.setTranslationsToday(translationPort.countHistoryAfter(todayStart));
                response.setTotalCharacters(translationPort.sumAllHistorySourceTextLength());
                response.setTotalDocumentTranslations(translationPort.countDocumentTranslations());
                response.setTotalGlossaries(glossaryPort.countAllGlossaries());

                response.setSystemStatus("normal");
            } finally {
                TenantContext.setBypassTenant(false);
            }

            return response;
        }

        /**
         * 获取用户翻译历史
         */
        public PageResponse<TranslationHistoryResponse> getTranslationHistory(Long userId, int page, int pageSize, String type) {
            var histories = translationTaskPort.getTranslationHistory(userId, page, pageSize, type);
            int total = translationTaskPort.countTranslationHistory(userId, type);

            var responseList = histories.stream()
                    .map(translationTaskPort::toHistoryResponse)
                    .toList();

            return PageResponse.of(page, pageSize, (long) total, responseList);
        }

        private UserPreferencesResponse buildDefaultPreferences() {
            UserPreferencesResponse response = new UserPreferencesResponse();
            response.setDefaultEngine("google");
            response.setDefaultTargetLang("zh");
            response.setEnableGlossary(true);
            response.setDefaultGlossaryId(null);
            response.setEnableCache(true);
            response.setAutoTranslateSelection(true);
            response.setFontSize(14);
            response.setThemeMode("light");
            return response;
        }

        private UserPreferencesResponse toPreferencesResponse(UserPreference pref) {
            UserPreferencesResponse response = new UserPreferencesResponse();
            response.setDefaultEngine(pref.getDefaultEngine());
            response.setDefaultTargetLang(pref.getDefaultTargetLang());
            response.setEnableGlossary(pref.getEnableGlossary());
            response.setDefaultGlossaryId(pref.getDefaultGlossaryId());
            response.setEnableCache(pref.getEnableCache());
            response.setAutoTranslateSelection(pref.getAutoTranslateSelection());
            response.setFontSize(pref.getFontSize());
            response.setThemeMode(pref.getThemeMode());
            return response;
        }

        private GlossaryResponse toGlossaryResponse(Glossary glossary) {
            GlossaryResponse response = new GlossaryResponse();
            response.setId(glossary.getId());
            response.setSourceWord(glossary.getSourceWord());
            response.setTargetWord(glossary.getTargetWord());
            response.setRemark(glossary.getRemark());
            response.setCreateTime(glossary.getCreateTime());
            return response;
        }
    }