package tech.easyflow.ai.service.impl;

import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import tech.easyflow.ai.constants.KnowledgeShareErrorCode;
import tech.easyflow.ai.entity.DocumentCollection;
import tech.easyflow.ai.entity.KnowledgeShare;
import tech.easyflow.ai.enums.KnowledgeShareStatus;
import tech.easyflow.ai.enums.KnowledgeShareType;
import tech.easyflow.ai.mapper.KnowledgeShareMapper;
import tech.easyflow.ai.service.DocumentCollectionService;
import tech.easyflow.ai.service.KnowledgeShareService;
import tech.easyflow.ai.vo.KnowledgeShareAuthContext;
import tech.easyflow.ai.vo.KnowledgeShareUrlCreateResult;
import tech.easyflow.common.web.exceptions.BusinessException;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Duration;
import java.util.Date;
import java.util.HexFormat;
import java.util.List;
import java.util.Set;
import java.util.UUID;

/**
 * 知识库分享服务实现。
 */
@Service
public class KnowledgeShareServiceImpl extends ServiceImpl<KnowledgeShareMapper, KnowledgeShare> implements KnowledgeShareService {

    private static final Duration DEFAULT_EXPIRE_DURATION = Duration.ofMinutes(30);

    @Resource
    private DocumentCollectionService documentCollectionService;

    @Override
    public KnowledgeShareUrlCreateResult createUrlShare(
        BigInteger knowledgeId,
        BigInteger tenantId,
        BigInteger deptId,
        BigInteger operatorId,
        String baseUrl,
        Set<String> permissionScopes
    ) {
        DocumentCollection knowledge = documentCollectionService.getById(knowledgeId);
        if (knowledge == null) {
            throw new BusinessException("知识库不存在");
        }
        invalidateExistingUrlShares(knowledgeId, operatorId);

        String shareKey = UUID.randomUUID().toString().replace("-", "");
        Date now = new Date();
        Date expiresAt = new Date(now.getTime() + DEFAULT_EXPIRE_DURATION.toMillis());

        KnowledgeShare share = new KnowledgeShare();
        share.setKnowledgeId(knowledgeId);
        share.setShareType(KnowledgeShareType.URL.name());
        share.setShareKeyHash(hashShareKey(shareKey));
        share.setStatus(KnowledgeShareStatus.ENABLED.name());
        share.setPermissionScopes(permissionScopes);
        share.setExpiresAt(expiresAt);
        share.setTenantId(tenantId);
        share.setDeptId(deptId);
        share.setCreated(now);
        share.setCreatedBy(operatorId);
        share.setModified(now);
        share.setModifiedBy(operatorId);
        save(share);

        KnowledgeShareUrlCreateResult result = new KnowledgeShareUrlCreateResult();
        result.setId(share.getId());
        result.setShareKey(shareKey);
        result.setExpiresAt(expiresAt);
        result.setShareUrl(buildShareUrl(baseUrl, shareKey));
        return result;
    }

    private void invalidateExistingUrlShares(BigInteger knowledgeId, BigInteger operatorId) {
        QueryWrapper wrapper = QueryWrapper.create()
            .eq(KnowledgeShare::getKnowledgeId, knowledgeId)
            .eq(KnowledgeShare::getShareType, KnowledgeShareType.URL.name())
            .eq(KnowledgeShare::getStatus, KnowledgeShareStatus.ENABLED.name());
        List<KnowledgeShare> activeShares = list(wrapper);
        if (activeShares == null || activeShares.isEmpty()) {
            return;
        }
        Date now = new Date();
        for (KnowledgeShare activeShare : activeShares) {
            KnowledgeShare update = new KnowledgeShare();
            update.setId(activeShare.getId());
            update.setStatus(KnowledgeShareStatus.DISABLED.name());
            update.setModified(now);
            update.setModifiedBy(operatorId);
            updateById(update);
        }
    }

    @Override
    public KnowledgeShareAuthContext validateUrlShare(String shareKey) {
        if (shareKey == null || shareKey.isBlank()) {
            throw invalidShare();
        }
        QueryWrapper wrapper = QueryWrapper.create()
            .eq(KnowledgeShare::getShareKeyHash, hashShareKey(shareKey));
        KnowledgeShare share = getOne(wrapper);
        if (share == null) {
            throw invalidShare();
        }
        if (KnowledgeShareStatus.REVOKED.name().equals(share.getStatus())
            || KnowledgeShareStatus.DISABLED.name().equals(share.getStatus())) {
            throw invalidShare();
        }
        if (share.getExpiresAt() == null || share.getExpiresAt().before(new Date())) {
            throw expiredShare();
        }
        DocumentCollection knowledge = documentCollectionService.getById(share.getKnowledgeId());
        if (knowledge == null) {
            throw invalidShare();
        }
        KnowledgeShareAuthContext context = new KnowledgeShareAuthContext();
        context.setShare(share);
        context.setKnowledge(knowledge);
        return context;
    }

    @Override
    public KnowledgeShareAuthContext assertUrlShareAccess(
        String shareKey,
        BigInteger knowledgeId,
        String actionScope
    ) {
        KnowledgeShareAuthContext context = validateUrlShare(shareKey);
        if (knowledgeId != null && context.getKnowledge() != null
            && context.getKnowledge().getId() != null
            && context.getKnowledge().getId().compareTo(knowledgeId) != 0) {
            throw invalidShare();
        }
        if (actionScope != null && !actionScope.isBlank()
            && !context.getShare().getPermissionScopeSet().contains(actionScope.trim().toUpperCase())) {
            throw forbiddenShare("当前分享不允许执行该操作");
        }
        return context;
    }

    private String buildShareUrl(String baseUrl, String shareKey) {
        if (baseUrl == null || baseUrl.isBlank()) {
            return null;
        }
        return baseUrl + (baseUrl.contains("?") ? "&" : "?")
            + "shareKey=" + shareKey;
    }

    private String hashShareKey(String shareKey) {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] value = digest.digest(shareKey.getBytes(StandardCharsets.UTF_8));
            return HexFormat.of().formatHex(value);
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException("SHA-256 unavailable", e);
        }
    }

    private BusinessException expiredShare() {
        return new BusinessException(KnowledgeShareErrorCode.KNOWLEDGE_SHARE_EXPIRED + ":链接已过期");
    }

    private BusinessException invalidShare() {
        return new BusinessException(KnowledgeShareErrorCode.KNOWLEDGE_SHARE_INVALID + ":链接无效");
    }

    private BusinessException forbiddenShare(String message) {
        return new BusinessException(KnowledgeShareErrorCode.KNOWLEDGE_SHARE_FORBIDDEN + ":" + message);
    }
}
