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

import cn.nianxx.thhotel.platform.message.common.dto.SourceMessageOriginalAccessAuditDraft;
import cn.nianxx.thhotel.platform.message.common.dto.SourceMessageOriginalContent;
import cn.nianxx.thhotel.platform.message.common.dto.SourceMessageOriginalMediaItem;
import cn.nianxx.thhotel.platform.message.common.enums.SourceMessageMediaType;
import cn.nianxx.thhotel.platform.message.common.enums.SourceMessageOriginalAccessResult;
import cn.nianxx.thhotel.platform.message.common.request.SourceMessageOriginalAccessRequest;
import cn.nianxx.thhotel.platform.message.common.result.SourceMessageOriginalMediaResponse;
import cn.nianxx.thhotel.platform.message.common.result.SourceMessageOriginalResponse;
import cn.nianxx.thhotel.platform.message.repository.SourceMessageInboxRepository;
import cn.nianxx.thhotel.platform.message.service.SourceMessageOriginalService;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * SourceMessage 原文读取服务实现。当前用受控访问口令替代尚未落地的角色权限体系。
 */
@Service
public class SourceMessageOriginalServiceImpl implements SourceMessageOriginalService {

    private final SourceMessageInboxRepository inboxRepository;
    private final String configuredAccessKey;

    /**
     * 注入 SourceMessage 持久化边界和原文读取访问口令，服务层负责审计写入。
     */
    public SourceMessageOriginalServiceImpl(
            SourceMessageInboxRepository inboxRepository,
            @Value("${source-message.original-read.access-key:}") String configuredAccessKey) {
        this.inboxRepository = inboxRepository;
        this.configuredAccessKey = configuredAccessKey;
    }

    /**
     * 校验原文读取口令。配置为空时默认关闭原文读取能力，避免误开放敏感正文和媒体 URL。
     */
    @Override
    public boolean canReadOriginal(String submittedAccessKey) {
        String configured = trimToNull(configuredAccessKey);
        return configured != null && configured.equals(submittedAccessKey);
    }

    /**
     * 读取 SourceMessage 原文并记录成功访问审计。普通摘要查询不会调用该方法。
     */
    @Override
    @Transactional
    public Optional<SourceMessageOriginalResponse> readOriginal(
            Long inboxId,
            SourceMessageOriginalAccessRequest request) {
        String actorId = requireText(request.actorId(), "actorId");
        String accessScene = requireText(request.accessScene(), "accessScene");
        Optional<SourceMessageOriginalContent> content = inboxRepository.findOriginalContent(inboxId);
        content.ifPresent(value -> inboxRepository.insertOriginalAccessAudit(new SourceMessageOriginalAccessAuditDraft(
                value.inboxId(),
                actorId,
                accessScene,
                SourceMessageOriginalAccessResult.GRANTED.code(),
                nowUtc()
        )));
        return content.map(this::toResponse);
    }

    /**
     * 将原文内容快照转换为 Controller 响应，并按媒体类型分组。
     */
    private SourceMessageOriginalResponse toResponse(SourceMessageOriginalContent content) {
        return new SourceMessageOriginalResponse(
                content.inboxId().toString(),
                content.textBody(),
                content.htmlBody(),
                true,
                filterMedia(content.mediaItems(), SourceMessageMediaType.INLINE_IMAGE.code()),
                filterMedia(content.mediaItems(), SourceMessageMediaType.ATTACHMENT.code())
        );
    }

    /**
     * 按媒体类型筛选原文响应媒体项，避免 Controller 了解媒体分类细节。
     */
    private List<SourceMessageOriginalMediaResponse> filterMedia(
            List<SourceMessageOriginalMediaItem> mediaItems,
            String mediaType) {
        if (mediaItems == null || mediaItems.isEmpty()) {
            return List.of();
        }
        return mediaItems.stream()
                .filter(item -> mediaType.equals(item.mediaType()))
                .map(this::toMediaResponse)
                .toList();
    }

    /**
     * 将原文读取内部媒体 DTO 转为 API 响应对象。
     */
    private SourceMessageOriginalMediaResponse toMediaResponse(SourceMessageOriginalMediaItem item) {
        return new SourceMessageOriginalMediaResponse(
                item.mediaType(),
                item.fileName(),
                item.contentType(),
                item.sizeBytes(),
                item.externalUrl(),
                item.externalMediaId()
        );
    }

    /**
     * 校验审计必填文本，保证访问记录可以追溯到调用方和使用场景。
     */
    private String requireText(String value, String fieldName) {
        String trimmed = trimToNull(value);
        if (trimmed == null) {
            throw new IllegalArgumentException(fieldName + " must not be blank");
        }
        return trimmed;
    }

    /**
     * 将空白字符串统一转换为空，避免空白访问口令或审计字段通过校验。
     */
    private String trimToNull(String value) {
        if (value == null) {
            return null;
        }
        String trimmed = value.trim();
        return trimmed.isEmpty() ? null : trimmed;
    }

    /**
     * 生成当前 UTC 时间，确保审计时间不依赖服务器本地时区。
     */
    private LocalDateTime nowUtc() {
        return LocalDateTime.now(ZoneOffset.UTC);
    }
}
