package com.datamate.datamanagement.infrastructure.persistence.repository.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.repository.CrudRepository;
import com.datamate.datamanagement.common.enums.KnowledgeSourceType;
import com.datamate.datamanagement.domain.model.knowledge.KnowledgeItem;
import com.datamate.datamanagement.infrastructure.persistence.mapper.KnowledgeItemMapper;
import com.datamate.datamanagement.infrastructure.persistence.repository.KnowledgeItemRepository;
import com.datamate.datamanagement.interfaces.dto.KnowledgeItemPagingQuery;
import com.datamate.datamanagement.interfaces.dto.KnowledgeItemSearchResponse;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * 知识条目仓储实现类
 */
@Repository
@RequiredArgsConstructor
public class KnowledgeItemRepositoryImpl extends CrudRepository<KnowledgeItemMapper, KnowledgeItem> implements KnowledgeItemRepository {
    private static final String PATH_SEPARATOR = "/";
    private final KnowledgeItemMapper knowledgeItemMapper;

    @Override
    public IPage<KnowledgeItem> findByCriteria(IPage<KnowledgeItem> page, KnowledgeItemPagingQuery query) {
        String relativePath = normalizeRelativePathPrefix(query.getRelativePath());
        LambdaQueryWrapper<KnowledgeItem> wrapper = new LambdaQueryWrapper<KnowledgeItem>()
            .eq(StringUtils.isNotBlank(query.getSetId()), KnowledgeItem::getSetId, query.getSetId())
            .eq(query.getContentType() != null, KnowledgeItem::getContentType, query.getContentType())
            .eq(query.getSourceType() != null, KnowledgeItem::getSourceType, query.getSourceType())
            .eq(StringUtils.isNotBlank(query.getSourceDatasetId()), KnowledgeItem::getSourceDatasetId, query.getSourceDatasetId())
            .eq(StringUtils.isNotBlank(query.getSourceFileId()), KnowledgeItem::getSourceFileId, query.getSourceFileId())
            .likeRight(StringUtils.isNotBlank(relativePath), KnowledgeItem::getRelativePath, relativePath);

        if (StringUtils.isNotBlank(query.getKeyword())) {
            wrapper.and(w -> w.like(KnowledgeItem::getSourceFileId, query.getKeyword())
                .or()
                .like(KnowledgeItem::getContent, query.getKeyword())
                .or()
                .like(KnowledgeItem::getRelativePath, query.getKeyword()));
        }

        wrapper.orderByDesc(KnowledgeItem::getCreatedAt);
        return knowledgeItemMapper.selectPage(page, wrapper);
    }

    @Override
    public long countBySetId(String setId) {
        return knowledgeItemMapper.selectCount(new LambdaQueryWrapper<KnowledgeItem>()
            .eq(KnowledgeItem::getSetId, setId));
    }

    @Override
    public List<KnowledgeItem> findAllBySetId(String setId) {
        return knowledgeItemMapper.selectList(new LambdaQueryWrapper<KnowledgeItem>()
            .eq(KnowledgeItem::getSetId, setId)
            .orderByDesc(KnowledgeItem::getCreatedAt));
    }

    @Override
    public long countBySourceTypes(List<KnowledgeSourceType> sourceTypes) {
        return knowledgeItemMapper.selectCount(new LambdaQueryWrapper<KnowledgeItem>()
            .in(KnowledgeItem::getSourceType, sourceTypes));
    }

    @Override
    public List<KnowledgeItem> findFileUploadItems() {
        return knowledgeItemMapper.selectList(new LambdaQueryWrapper<KnowledgeItem>()
            .eq(KnowledgeItem::getSourceType, KnowledgeSourceType.FILE_UPLOAD)
            .select(KnowledgeItem::getId, KnowledgeItem::getContent, KnowledgeItem::getSourceFileId));
    }

    @Override
    public IPage<KnowledgeItemSearchResponse> searchFileItems(IPage<?> page, String keyword) {
        return knowledgeItemMapper.searchFileItems(page, keyword);
    }

    @Override
    public Long sumDatasetFileSize() {
        return knowledgeItemMapper.sumDatasetFileSize();
    }

    @Override
    public boolean existsBySetIdAndRelativePath(String setId, String relativePath) {
        if (StringUtils.isBlank(setId) || StringUtils.isBlank(relativePath)) {
            return false;
        }
        return knowledgeItemMapper.selectCount(new LambdaQueryWrapper<KnowledgeItem>()
            .eq(KnowledgeItem::getSetId, setId)
            .eq(KnowledgeItem::getRelativePath, relativePath)) > 0;
    }

    @Override
    public int removeByRelativePathPrefix(String setId, String relativePath) {
        String normalized = normalizeRelativePathValue(relativePath);
        if (StringUtils.isBlank(setId) || StringUtils.isBlank(normalized)) {
            return 0;
        }
        String prefix = normalizeRelativePathPrefix(normalized);
        LambdaQueryWrapper<KnowledgeItem> wrapper = new LambdaQueryWrapper<KnowledgeItem>()
            .eq(KnowledgeItem::getSetId, setId)
            .and(w -> w.eq(KnowledgeItem::getRelativePath, normalized)
                .or()
                .likeRight(KnowledgeItem::getRelativePath, prefix));
        return knowledgeItemMapper.delete(wrapper);
    }

    private String normalizeRelativePathPrefix(String relativePath) {
        if (StringUtils.isBlank(relativePath)) {
            return "";
        }
        String normalized = relativePath.replace("\\", PATH_SEPARATOR).trim();
        while (normalized.startsWith(PATH_SEPARATOR)) {
            normalized = normalized.substring(1);
        }
        if (StringUtils.isBlank(normalized)) {
            return "";
        }
        if (!normalized.endsWith(PATH_SEPARATOR)) {
            normalized = normalized + PATH_SEPARATOR;
        }
        return normalized;
    }

    private String normalizeRelativePathValue(String relativePath) {
        if (StringUtils.isBlank(relativePath)) {
            return "";
        }
        String normalized = relativePath.replace("\\", PATH_SEPARATOR).trim();
        while (normalized.startsWith(PATH_SEPARATOR)) {
            normalized = normalized.substring(1);
        }
        while (normalized.endsWith(PATH_SEPARATOR)) {
            normalized = normalized.substring(0, normalized.length() - 1);
        }
        return normalized;
    }
}
