package com.microservices.zone.search.service.impl;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.microservices.common.core.domain.R;
import com.microservices.common.core.exception.ServiceException;
import com.microservices.common.core.utils.StringUtils;
import com.microservices.common.httpClient.service.HttpAPIService;
import com.microservices.common.redis.service.RedisService;
import com.microservices.common.security.utils.SecurityUtils;
import com.microservices.system.api.RemoteFileService;
import com.microservices.system.api.domain.SysFileInfo;
import com.microservices.system.api.model.LoginUser;
import com.microservices.zone.project.domain.ZoneProject;
import com.microservices.zone.project.domain.ZoneProjectWithScore;
import com.microservices.zone.project.domain.vo.GitLinkProjectSearchVo;
import com.microservices.zone.project.domain.vo.ZoneProjectDataVo;
import com.microservices.zone.project.mapper.ZoneProjectMapper;
import com.microservices.zone.project.service.IZoneProjectService;
import com.microservices.zone.resource.domain.ZoneResourceWithScore;
import com.microservices.zone.resource.mapper.ZoneResourceMapper;
import com.microservices.zone.member.domain.ZoneMemberWithScore;
import com.microservices.zone.member.mapper.ZoneMemberMapper;
import com.microservices.zone.search.dto.*;
import com.microservices.zone.search.service.IGlobalSearchService;
import com.microservices.zone.search.utils.SearchUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.commons.config.DefaultsBindHandlerAdvisor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;
import java.util.regex.Pattern;

/**
 * 全局搜索服务实现
 *
 * @author microservices
 */
@Service
public class GlobalSearchServiceImpl implements IGlobalSearchService {

    private static final Logger logger = LoggerFactory.getLogger(GlobalSearchServiceImpl.class);

    @Autowired
    private ZoneProjectMapper zoneProjectMapper;

    @Autowired
    private ZoneResourceMapper zoneResourceMapper;

    @Autowired
    private ZoneMemberMapper zoneMemberMapper;

    @Autowired
    private RemoteFileService remoteFileService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private IZoneProjectService projectService;
    @Autowired
    private HttpAPIService httpAPIService;

    @Value("${http.gitLinkSearchUrl:}")
    public String gitLinkSearchUrl;

    private static final String SEARCH_CACHE_PREFIX = "search:cache:";
    private static final long CACHE_EXPIRE_SECONDS = 300; // 5分钟
    @Autowired
    private DefaultsBindHandlerAdvisor.MappingsProvider mappingsProvider;

    @Override
    public GlobalSearchResponse globalSearch(GlobalSearchRequest request) {
        long startTime = System.currentTimeMillis();

        if (request.getZoneId() == null) {
            throw new ServiceException("专区id不能为空");
        }

        // 2. 并行搜索各类型
        List<GlobalSearchResult> allResults = new ArrayList<>();
        Map<String, Long> typeCounts = new HashMap<>();

        // 获取当前用户信息
        LoginUser loginUser = SecurityUtils.getLoginUser();

        // 确定要搜索的类型
        List<String> searchTypes = request.getTypes();
        if (searchTypes == null || searchTypes.isEmpty()) {
            searchTypes = Arrays.asList("zone_project", "resource", "member");
        }
        Long searchTotal = 0L;

        // 搜索Zone项目
        if (searchTypes.contains("zone_project")) {
            GlobalSearchResultDataVo resultDataVo = searchZoneProjects(request);
            allResults.addAll(resultDataVo.getGlobalSearchResultList());
            typeCounts.put("zone_project", resultDataVo.getTotal());
            searchTotal += resultDataVo.getTotal();
        }

        // 搜索Zone资源
        if (searchTypes.contains("resource")) {
            List<GlobalSearchResult> resourceResults = searchResources(request);
            allResults.addAll(resourceResults);
            Long searchResourceCount = zoneResourceMapper.globalSearchCount(request.getKeyword(), request.getZoneId());
            typeCounts.put("resource", searchResourceCount);
            searchTotal += searchResourceCount;
        }

        // 搜索Zone会员
        if (searchTypes.contains("member")) {
            List<GlobalSearchResult> memberResults = searchZoneMembers(request);
            allResults.addAll(memberResults);
            Long searchMemberCount = zoneMemberMapper.globalSearchCount(request.getKeyword(), request.getZoneId());
            typeCounts.put("member", searchMemberCount);
            searchTotal += searchMemberCount;
        }

        // 3. 按相关度评分排序
        allResults.sort((a, b) -> {
            if (b.getScore() != null && a.getScore() != null) {
                return b.getScore().compareTo(a.getScore());
            }
            return 0;
        });

        // 4. 分页
        int total = allResults.size();
        int start = (request.getPageNum() - 1) * request.getPageSize();
        int end = Math.min(start + request.getPageSize(), total);
        List<GlobalSearchResult> pagedResults = start < total ?
                allResults.subList(start, end) : new ArrayList<>();

        // 5. 构建响应
        GlobalSearchResponse response = new GlobalSearchResponse();
        response.setTotal(searchTotal);
        response.setResults(pagedResults);
        response.setTypeCounts(typeCounts);
        response.setKeyword(request.getKeyword());
        response.setPageNum(request.getPageNum());
        response.setPageSize(request.getPageSize());
        response.setSearchTime(System.currentTimeMillis() - startTime);

        // 7. 异步记录搜索日志
        recordSearchLog(request, response, loginUser);

        return response;
    }

    /**
     * 异步记录搜索日志
     */
    @Async
    public void recordSearchLog(GlobalSearchRequest request, GlobalSearchResponse response, LoginUser loginUser) {
        try {
            logger.info("全局搜索 - 关键词: {}, 用户ID: {}, 耗时: {}ms, 结果数: {}, 搜索类型: {}, 专区ID: {}",
                    request.getKeyword(),
                    loginUser != null ? loginUser.getUserId() : null,
                    response.getSearchTime(),
                    response.getTotal(),
                    request.getTypes() != null ? String.join(",", request.getTypes()) : null,
                    request.getZoneId()
            );
        } catch (Exception e) {
            logger.error("记录搜索日志失败: {}", e.getMessage());
        }
    }

    /**
     * 搜索Zone项目
     */
    private GlobalSearchResultDataVo searchZoneProjects(GlobalSearchRequest request) {
        GlobalSearchResultDataVo globalSearchResultDataVo = new GlobalSearchResultDataVo();
        List<GlobalSearchResult> results = new ArrayList<>();
        Long total = 0L;
        try {
            if (StringUtils.isNotEmpty(gitLinkSearchUrl)) {
                Long projectTypeId = null;
                String topic = null;
                if (request.getExtraSearchParam() != null) {
                    projectTypeId = request.getExtraSearchParam().getLong("projectTypeId");
                    topic = request.getExtraSearchParam().getString("topic");
                }
                List<String> gitlinkProjectIds = zoneProjectMapper.selectZoneProjectGitlinkIdList(request.getZoneId(), projectTypeId);

                JSONObject searchRes = httpAPIService.doGet(request.toProjectEsSearchString(gitLinkSearchUrl, String.join(",", gitlinkProjectIds), topic));
                GitlinkSearchDataVo gitlinkSearchDataVos = gitlinkSearchResToGitlinkSearchDataVo(searchRes);
                total = gitlinkSearchDataVos.getTotal();
                if (gitlinkSearchDataVos.getTotal() > 0) {
                    List<GitlinkSearchVo> gitlinkSearchVoList = gitlinkSearchDataVos.getGitlinkSearchVoList();
                    List<Long> gitlinkProjectIdList = gitlinkSearchVoList.stream().map(GitlinkSearchVo::getInstanceId).collect(Collectors.toList());
                    List<ZoneProject> zoneProjectList = zoneProjectMapper.selectZoneProjectListFromGitlinkProjectIdList(request.getZoneId(), gitlinkProjectIdList);
                    List<ZoneProjectDataVo> projectDataVoList = projectService.toZoneProjectDataVoList(zoneProjectList);
                    for (GitlinkSearchVo gitlinkSearchVo : gitlinkSearchVoList) {
                        ZoneProjectDataVo zoneProjectDataVo = projectDataVoList.stream().filter(x -> x.getGitlinkProjectId().equals(gitlinkSearchVo.getInstanceId())).findFirst().orElse(null);
                        if (zoneProjectDataVo != null) {
                            GlobalSearchResult result = gitlinkSearchVo.toGlobalSearchResult(zoneProjectDataVo, topic);
                            results.add(result);
                        }
                    }
                }
            } else {
                List<ZoneProjectWithScore> projects = zoneProjectMapper.globalSearchWithScore(
                        request.getKeyword(),
                        request.getZoneId(),
                        (request.getPageNum() - 1) * request.getPageSize(),
                        request.getPageSize()
                );
                total = zoneProjectMapper.globalSearchCount(request.getKeyword(), request.getZoneId());
                List<ZoneProject> zoneProjectList = projects.stream().map(x -> (ZoneProject) x).collect(Collectors.toList());
                List<ZoneProjectDataVo> projectDataVoList = projectService.toZoneProjectDataVoList(zoneProjectList);

                for (ZoneProjectWithScore project : projects) {
                    ZoneProjectDataVo zoneProjectDataVo = projectDataVoList.stream().filter(x -> x.getId().equals(project.getId())).findFirst().orElse(null);
                    GlobalSearchResult result = project.toGlobalSearchResult(zoneProjectDataVo);
                    result.setTitle(SearchUtils.highlightKeyword(result.getTitle(), request.getKeyword()));
                    result.setContent(SearchUtils.highlightKeyword(result.getContent(), request.getKeyword()));
                    results.add(result);
                }
            }
        } catch (Exception e) {
            System.err.println("搜索Zone项目失败: " + e.getMessage());
        }
        globalSearchResultDataVo.setTotal(total);
        globalSearchResultDataVo.setGlobalSearchResultList(results);
        return globalSearchResultDataVo;
    }

    private GitlinkSearchDataVo gitlinkSearchResToGitlinkSearchDataVo(JSONObject gitlinkSearchRes) {

        GitlinkSearchDataVo gitlinkSearchDataVo = new GitlinkSearchDataVo();
        List<GitlinkSearchVo> results = new ArrayList<>();
        if (gitlinkSearchRes != null && gitlinkSearchRes.getJSONObject("data") != null) {
            JSONObject data = gitlinkSearchRes.getJSONObject("data");
            if (data.getLong("total") == null || data.getLong("total") == 0) {
                gitlinkSearchDataVo.setGitlinkSearchVoList(results);
                return gitlinkSearchDataVo;
            }
            gitlinkSearchDataVo.setTotal(data.getLong("total"));
            JSONArray rows = data.getJSONArray("rows");
            for (int i = 0; i < rows.size(); i++) {
                JSONObject row = rows.getJSONObject(i);
                results.add(row.toJavaObject(GitlinkSearchVo.class));
            }
            gitlinkSearchDataVo.setGitlinkSearchVoList(results);
        }

        return gitlinkSearchDataVo;
    }

    /**
     * 搜索Zone资源
     */
    private List<GlobalSearchResult> searchResources(GlobalSearchRequest request) {
        List<GlobalSearchResult> results = new ArrayList<>();
        try {
            List<ZoneResourceWithScore> resources = zoneResourceMapper.globalSearchWithScore(
                    request.getKeyword(),
                    request.getZoneId(),
                    (request.getPageNum() - 1) * request.getPageSize(),
                    request.getPageSize()
            );

            for (ZoneResourceWithScore resource : resources) {
                GlobalSearchResult result = new GlobalSearchResult();
                result.setType("resource");
                result.setId(resource.getId());
                result.setTitle(SearchUtils.highlightKeyword(resource.getName(), request.getKeyword()));
                result.setContent(SearchUtils.highlightKeyword(resource.getSummary(), request.getKeyword()));
                result.setDeptId(resource.getDeptId());
                result.setZoneId(resource.getZoneId());
                result.setCreateTime(resource.getCreateTime());

                // 使用数据库返回的实际搜索评分
                Double score = resource.getSearchScore();
                if (score == null || score == 0.0) {
                    score = 0.1; // LIKE 匹配的最小评分
                }
                result.setScore(score);

                // 查询并过滤匹配的附件
                if (StringUtils.isNotEmpty(resource.getFileIds())) {
                    try {
                        JSONObject extendData = new JSONObject();
                        extendData.put("downloadCount", resource.getDownloadCount());
                        if (resource.getFileIds() != null) {
                            String[] fileIds = resource.getFileIds().split(",");
                            extendData.put("fileCount", fileIds.length);
                        }


                        R<List<SysFileInfo>> fileResponse = remoteFileService.getFileList(resource.getFileIds());
                        if (fileResponse != null && fileResponse.getCode() == 200 && fileResponse.getData() != null) {
                            List<JSONObject> matchedFiles = fileResponse.getData().stream()
                                    .filter(file -> StringUtils.isNotEmpty(file.getFileOriginName())
                                            && file.getFileOriginName().toLowerCase().contains(request.getKeyword().toLowerCase()))
                                    .map(file -> {
                                        JSONObject fileInfo = new JSONObject();
                                        fileInfo.put("fileId", file.getFileId());
                                        fileInfo.put("fileName", SearchUtils.highlightKeyword(file.getFileOriginName(), request.getKeyword()));
                                        fileInfo.put("fileSize", file.getFileSizeInfo());
                                        return fileInfo;
                                    })
                                    .collect(Collectors.toList());

                            if (!matchedFiles.isEmpty()) {

                                extendData.put("matchedFiles", matchedFiles);

                            }
                        }
                        result.setExtendData(extendData);
                    } catch (Exception e) {
                        logger.warn("查询附件信息失败: resourceId={}, error={}", resource.getId(), e.getMessage());
                    }
                }

                results.add(result);
            }
        } catch (Exception e) {
            logger.error("搜索Zone资源失败: {}", e.getMessage());
        }
        return results;
    }

    /**
     * 搜索Zone会员
     */
    private List<GlobalSearchResult> searchZoneMembers(GlobalSearchRequest request) {
        List<GlobalSearchResult> results = new ArrayList<>();
        try {
            List<ZoneMemberWithScore> members = zoneMemberMapper.globalSearchWithScore(
                    request.getKeyword(),
                    request.getZoneId(),
                    (request.getPageNum() - 1) * request.getPageSize(),
                    request.getPageSize()
            );

            for (ZoneMemberWithScore member : members) {
                GlobalSearchResult result = new GlobalSearchResult();
                result.setType("member");
                result.setId(member.getId());
                result.setTitle(SearchUtils.highlightKeyword(member.getName(), request.getKeyword()));

                // 构建内容：用户名 + 会员介绍
                StringBuilder content = new StringBuilder();
                if (member.getSysUser() != null && StringUtils.isNotEmpty(member.getSysUser().getUserName())) {
                    content.append("用户名: ").append(member.getSysUser().getUserName());
                }
                if (StringUtils.isNotEmpty(member.getIntroduction())) {
                    if (content.length() > 0) {
                        content.append(" | ");
                    }
                    content.append(member.getIntroduction());
                }
                result.setContent(SearchUtils.highlightKeyword(content.toString(), request.getKeyword()));

                result.setDeptId(member.getDeptId());
                result.setZoneId(member.getZoneId());
                result.setCreateTime(member.getCreateTime());

                // 使用数据库返回的实际搜索评分
                Double score = member.getSearchScore();
                if (score == null || score == 0.0) {
                    score = 0.1; // LIKE 匹配（包括用户名匹配）的最小评分
                }
                result.setScore(score);

                // 添加扩展数据
                if (StringUtils.isNotEmpty(member.getImageUrl()) || member.getMemberLevelId() != null) {
                    try {
                        JSONObject extendData = new JSONObject();
                        if (StringUtils.isNotEmpty(member.getImageUrl())) {
                            extendData.put("imageUrl", member.getImageUrl());
                        }
                        if (StringUtils.isNotEmpty(member.getMemberTypeName())) {
                            extendData.put("memberTypeName", member.getMemberTypeName());
                        }
                        if (member.getSysUser() != null) {
                            extendData.put("username", member.getSysUser().getUserName());
                        }


                        result.setExtendData(extendData);
                    } catch (Exception e) {
                        logger.warn("构建会员扩展数据失败: memberId={}, error={}", member.getId(), e.getMessage());
                    }
                }

                results.add(result);
            }
        } catch (Exception e) {
            logger.error("搜索Zone会员失败: {}", e.getMessage());
        }
        return results;
    }

    /**
     * 构建缓存键
     */
    private String buildCacheKey(GlobalSearchRequest request) {
        StringBuilder key = new StringBuilder(request.getKeyword());
        if (request.getTypes() != null && !request.getTypes().isEmpty()) {
            key.append(":").append(String.join(",", request.getTypes()));
        }
        if (request.getZoneId() != null) {
            key.append(":zone=").append(request.getZoneId());
        }
        return key.toString();
    }

    /**
     * 构建空响应
     */
    private GlobalSearchResponse buildEmptyResponse(GlobalSearchRequest request) {
        GlobalSearchResponse response = new GlobalSearchResponse();
        response.setTotal(0L);
        response.setResults(new ArrayList<>());
        response.setTypeCounts(new HashMap<>());
        response.setKeyword(request.getKeyword());
        response.setPageNum(request.getPageNum());
        response.setPageSize(request.getPageSize());
        response.setSearchTime(0L);
        return response;
    }
}
