package cn.com.poc.human_resources.aggregate.impl;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import cn.com.gsst.dify_client.DifyChatClient;
import cn.com.gsst.dify_client.DifyClientFactory;
import cn.com.gsst.dify_client.DifyWorkflowClient;
import cn.com.gsst.dify_client.callback.ChatStreamCallback;
import cn.com.gsst.dify_client.enums.FileTransferMethod;
import cn.com.gsst.dify_client.enums.FileType;
import cn.com.gsst.dify_client.enums.ResponseMode;
import cn.com.gsst.dify_client.event.MessageEndEvent;
import cn.com.gsst.dify_client.event.MessageEvent;
import cn.com.gsst.dify_client.exception.DifyApiException;
import cn.com.gsst.dify_client.model.chat.ChatMessage;
import cn.com.gsst.dify_client.model.chat.ChatMessageResponse;
import cn.com.gsst.dify_client.model.file.FileInfo;
import cn.com.gsst.dify_client.model.workflow.WorkflowRunRequest;
import cn.com.gsst.dify_client.model.workflow.WorkflowRunResponse;
import cn.com.poc.common.constant.CommonConstant;
import cn.com.poc.common.utils.DateUtils;
import cn.com.poc.common.utils.DocumentLoad;
import cn.com.poc.common.utils.JsonUtils;
import cn.com.poc.common.utils.SSEUtil;
import cn.com.poc.common.utils.StringUtils;
import cn.com.poc.human_resources.aggregate.HumanResourceService;
import cn.com.poc.human_resources.constant.HumanResourcePositionConstant;
import cn.com.poc.human_resources.convert.BizHumanResourceResumeConvert;
import cn.com.poc.human_resources.entity.BizHumanResourcePositionEntity;
import cn.com.poc.human_resources.entity.BizHumanResourceResumeContentEntity;
import cn.com.poc.human_resources.entity.BizHumanResourceResumeEntity;
import cn.com.poc.human_resources.entity.HumanResourcePositionBaseInfo;
import cn.com.poc.human_resources.entity.HumanResourceResumeNaturalLanguageRetrievalLogEntity;
import cn.com.poc.human_resources.entity.position.BaseInfo;
import cn.com.poc.human_resources.entity.position.Job;
import cn.com.poc.human_resources.entity.position.Por;
import cn.com.poc.human_resources.entity.resume.Resume;
import cn.com.poc.human_resources.query.PositionListQueryCondition;
import cn.com.poc.human_resources.query.PositionListQueryItem;
import cn.com.poc.human_resources.query.ResumeContentQueryItem;
import cn.com.poc.human_resources.query.ResumeQueryCondition;
import cn.com.poc.human_resources.query.ResumeQueryItem;
import cn.com.poc.human_resources.service.BizHumanResourcePositionService;
import cn.com.poc.human_resources.service.BizHumanResourceResumeContentService;
import cn.com.poc.human_resources.service.BizHumanResourceResumeService;
import cn.com.poc.human_resources.service.HumanResourceResumeNaturalLanguageRetrievalLogService;
import cn.com.poc.thirdparty.resource.demand.ai.entity.largemodel.LargeModelDemandResult;
import cn.com.yict.framemax.core.exception.BusinessException;
import cn.com.yict.framemax.data.model.PagingInfo;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * @author alex.yao
 * @date 2025/9/28
 */
@Service
public class HumanResourceServiceImpl implements HumanResourceService {

    private String DIFY_BASE_URL = "https://dify.gsstcloud.com/v1";

    @Resource
    private BizHumanResourcePositionService bizHumanResourcePositionService;

    @Resource
    private BizHumanResourceResumeService bizHumanResourceResumeService;

    @Resource
    private BizHumanResourceResumeContentService bizHumanResourceResumeContentService;

    @Resource
    private HumanResourceResumeNaturalLanguageRetrievalLogService humanResourceResumeNaturalLanguageRetrievalLogService;

    @Override
    @Retryable(value = Exception.class, maxAttempts = 2, backoff = @Backoff(delay = 1000, multiplier = 2))
    public Resume uploadResume(String fileURL, Long positionId, Long userId) throws Exception {
        BizHumanResourcePositionEntity bizHumanResourcePositionEntity = bizHumanResourcePositionService.get(positionId);
        if (bizHumanResourcePositionEntity == null) {
            throw new BusinessException("该岗位信息不存在");
        }
        Map<String, Object> inputs = new LinkedHashMap<>();
        inputs.put("position", JsonUtils.serialize(bizHumanResourcePositionEntity));

        List<FileInfo> files = new ArrayList<>();
        files.add(FileInfo.builder()
                .type(FileType.DOCUMENT)
                .transferMethod(FileTransferMethod.REMOTE_URL)
                .url(fileURL)
                .build());

        // 创建聊天客户端
        DifyChatClient chatClient = DifyClientFactory.createChatClient(DIFY_BASE_URL, "app-1MRun3ecfLOzFS96xcWYCOOX");

        // 创建聊天消息
        ChatMessage message = ChatMessage.builder()
                .query("run")
                .user(userId.toString())
                .files(files)
                .inputs(inputs)
                .responseMode(ResponseMode.BLOCKING)
                .build();

        // 发送消息并获取响应
        ChatMessageResponse response = chatClient.sendChatMessage(message);
        if (response == null || StringUtils.isBlank(response.getAnswer())) {
            throw new BusinessException("提取简历失败");
        }
        Resume resume = JsonUtils.deSerialize(response.getAnswer(), Resume.class);
        if (resume == null) {
            throw new BusinessException("提取简历异常");
        }
        BizHumanResourceResumeEntity bizHumanResourceResumeEntity =
                this.saveResume(userId, fileURL, positionId, resume);
        if (bizHumanResourceResumeEntity == null) {
            throw new BusinessException("保存简历信息失败");
        }
        this.saveResumeContent(fileURL, positionId, bizHumanResourceResumeEntity.getId());
        return resume;
    }


    @Override
    public void positionAssistant(String demand, String type, String fileInfos, String jobInformation, String question,
                                  String dialoguesId, Long userId)
            throws DifyApiException, IOException, InterruptedException {
        // 创建聊天客户端
        DifyChatClient chatClient = DifyClientFactory.createChatClient(DIFY_BASE_URL, "app-YmVPoXmTh7ejERFbip3ADCYN");
        Map<String, Object> inputs = new LinkedHashMap<>();
        inputs.put("type", type);
        if (StringUtils.isNotBlank(demand)) {
            inputs.put("demand", demand);
        }
        if (StringUtils.isNotBlank(jobInformation)) {
            inputs.put("jobInfomations", jobInformation);
        }
        if (StringUtils.isNotBlank(fileInfos)) {
            inputs.put("fileinfos", fileInfos);
        }
        // 创建聊天消息
        ChatMessage message = ChatMessage.builder()
                .query(StringUtils.isBlank(question) ? "run" : question)
                .user(userId.toString())
                .inputs(inputs)
                .conversationId(StringUtils.isNotBlank(dialoguesId) ? dialoguesId : StringUtils.EMPTY)
                .responseMode(ResponseMode.STREAMING)
                .build();

        CountDownLatch countDownLatch = new CountDownLatch(1);
        ServletRequestAttributes servletRequestAttributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletResponse response = servletRequestAttributes.getResponse();
        // 发送消息并获取响应
        chatClient.sendChatMessageStream(message, new ChatStreamCallback() {
            SSEUtil sseUtil = new SSEUtil(response);

            @Override
            public void onMessage(MessageEvent event) {
                try {
                    if (StringUtils.isNotEmpty(event.getAnswer())) {
                        LargeModelDemandResult largeModelDemandResult = new LargeModelDemandResult();
                        largeModelDemandResult.setCode("0");
                        largeModelDemandResult.setMessage(event.getAnswer());
                        sseUtil.send(JsonUtils.serialize(event.getAnswer()));
                    }
                } catch (IOException e) {
                    sseUtil.completeByError(e.getMessage());
                    throw new RuntimeException(e);
                }
            }

            @Override
            public void onMessageEnd(MessageEndEvent event) {
                try {
                    sseUtil.send("[DONE]");
                } catch (IOException e) {
                    sseUtil.completeByError(e.getMessage());
                    throw new RuntimeException(e);
                } finally {
                    sseUtil.complete();
                    countDownLatch.countDown();
                }
            }
        });
        countDownLatch.await(60, TimeUnit.SECONDS);
    }


    @Override
    public BizHumanResourcePositionEntity saveOrUpdatePosition(BaseInfo baseInfo, Job job, Por por, Long id,
                                                               Long memberId) throws Exception {

        BizHumanResourcePositionEntity bizHumanResourcePositionEntity = new BizHumanResourcePositionEntity();
        bizHumanResourcePositionEntity.setId(id);
        bizHumanResourcePositionEntity.setPostStatus(HumanResourcePositionConstant.POST_STATUS.DRAFT);
        bizHumanResourcePositionEntity.setJobTitle(baseInfo.getJobTitle());
        bizHumanResourcePositionEntity.setDepartment(baseInfo.getDepartment());
        bizHumanResourcePositionEntity.setWorkLocation(baseInfo.getWorkLocation());
        bizHumanResourcePositionEntity.setJobNature(baseInfo.getJobNature());
        bizHumanResourcePositionEntity.setNumberOfRecruits(baseInfo.getNumberOfRecruits());
        bizHumanResourcePositionEntity.setWorkExperience(baseInfo.getWorkExperience());
        bizHumanResourcePositionEntity.setEducationalRe(baseInfo.getEducationalRe());
        bizHumanResourcePositionEntity.setSalaryRange(baseInfo.getSalaryRange());

        bizHumanResourcePositionEntity.setJobRequirements(job.getJobRequirements());
        bizHumanResourcePositionEntity.setJobDuties(job.getJobDuties());

        bizHumanResourcePositionEntity.setEssential(
                MapUtils.isNotEmpty(por.getEssential()) ? JsonUtils.serialize(por.getEssential()) : null);
        bizHumanResourcePositionEntity.setBonusPoints(
                MapUtils.isNotEmpty(por.getBonusPoints()) ? JsonUtils.serialize(por.getBonusPoints()) : null);
        bizHumanResourcePositionEntity.setExclusion(
                MapUtils.isNotEmpty(por.getExclusion()) ? JsonUtils.serialize(por.getExclusion()) : null);

        bizHumanResourcePositionEntity.setMemberId(memberId);
        return id != null ? bizHumanResourcePositionService.update(bizHumanResourcePositionEntity) :
                bizHumanResourcePositionService.save(bizHumanResourcePositionEntity);
    }

    @Override
    public List<HumanResourcePositionBaseInfo> listPositions(Long userId, PagingInfo pagingInfo) throws Exception {
        PositionListQueryCondition condition = new PositionListQueryCondition();
        condition.setMemberId(userId);
        List<PositionListQueryItem> positionListQueryItems =
                bizHumanResourcePositionService.positionListQuery(condition, pagingInfo);
        List<HumanResourcePositionBaseInfo> result = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(positionListQueryItems)) {
            result = positionListQueryItems.stream().map(item -> {
                HumanResourcePositionBaseInfo baseInfo = new HumanResourcePositionBaseInfo();
                baseInfo.setId(item.getId());
                baseInfo.setPostStatus(item.getPostStatus());
                baseInfo.setJobTitle(item.getJobTitle());
                baseInfo.setWorkLocation(item.getWorkLocation());
                baseInfo.setJobNature(item.getJobNature());
                baseInfo.setWorkExperience(item.getWorkExperience());
                baseInfo.setResumeCount(item.getResumeCount());
                return baseInfo;
            }).collect(Collectors.toList());
        }
        return result;
    }

    @Override
    public BizHumanResourcePositionEntity getPositionDetail(Long userId, Long positionId) throws Exception {
        BizHumanResourcePositionEntity bizHumanResourcePositionEntity = new BizHumanResourcePositionEntity();
        bizHumanResourcePositionEntity.setId(positionId);
        bizHumanResourcePositionEntity.setMemberId(userId);
        bizHumanResourcePositionEntity.setIsDeleted(CommonConstant.IsDeleted.N);
        List<BizHumanResourcePositionEntity> entities =
                bizHumanResourcePositionService.findByExample(bizHumanResourcePositionEntity, null);
        if (CollectionUtils.isEmpty(entities)) {
            return null;
        }
        return entities.get(0);
    }

    @Override
    public void deletePositions(Long userId, Long... positionIds) throws Exception {
        if (userId == null) {
            throw new BusinessException("用户未登录");
        }
        if (positionIds == null || positionIds.length == 0) {
            return;
        }
        String lock = "deletePositions" + userId;
        synchronized (lock.intern()) {
            for (Long positionId : positionIds) {
                bizHumanResourcePositionService.deletedById(positionId);
            }
        }
    }

    @Override
    public String publishPositions(Long id, Long memberId) throws Exception {
        return updatePostStatus(id, memberId, HumanResourcePositionConstant.POST_STATUS.PUBLISHED);
    }

    @Override
    public String unPublishPositions(Long id, Long memberId) throws Exception {
        return updatePostStatus(id, memberId, HumanResourcePositionConstant.POST_STATUS.DRAFT);
    }

    /**
     * 更新岗位发布状态
     */
    private String updatePostStatus(Long id, Long memberId, String postStatus) throws Exception {
        BizHumanResourcePositionEntity bizHumanResourcePositionEntity = bizHumanResourcePositionService.get(id);
        if (bizHumanResourcePositionEntity == null ||
                !Objects.equals(bizHumanResourcePositionEntity.getMemberId(), memberId)) {
            throw new BusinessException("数据异常，无法查到当前岗位信息");
        }
        bizHumanResourcePositionEntity.setPostStatus(postStatus);
        bizHumanResourcePositionService.update(bizHumanResourcePositionEntity);
        return bizHumanResourcePositionEntity.getPostStatus();
    }

    @Override
    public BizHumanResourceResumeEntity saveResume(Long userId, String fileURL, Long positionId, Resume resume)
            throws Exception {
        BizHumanResourceResumeEntity bizHumanResourceResumeEntity =
                BizHumanResourceResumeConvert.resumeToEntity(resume);
        bizHumanResourceResumeEntity.setMemberId(userId);
        bizHumanResourceResumeEntity.setPosition(positionId);
        bizHumanResourceResumeEntity.setFileUrl(fileURL);
        return bizHumanResourceResumeService.save(bizHumanResourceResumeEntity);
    }

    @Override
    public BizHumanResourceResumeEntity updateResume(Long id, Long userId, String fileURL, Long positionId,
                                                     Resume resume) throws Exception {
        BizHumanResourceResumeEntity bizHumanResourceResumeEntity =
                BizHumanResourceResumeConvert.resumeToEntity(resume);
        bizHumanResourceResumeEntity.setId(id);
        bizHumanResourceResumeEntity.setMemberId(userId);
        bizHumanResourceResumeEntity.setPosition(positionId);
        bizHumanResourceResumeEntity.setFileUrl(fileURL);
        return bizHumanResourceResumeService.update(bizHumanResourceResumeEntity);
    }

    @Override
    public List<BizHumanResourceResumeEntity> listResumes(Long userId, Long positionId, PagingInfo pagingInfo)
            throws Exception {
        ResumeQueryCondition condition = new ResumeQueryCondition();
        condition.setPositionId(positionId);
        condition.setMemberId(userId);
        List<ResumeQueryItem> resumeQueryItems = bizHumanResourceResumeService.resumeQuery(condition, pagingInfo);
        return resumeQueryItems.stream().map(BizHumanResourceResumeConvert::resumeQueryItemToEntity)
                .collect(Collectors.toList());
    }

    @Override
    public List<BizHumanResourceResumeEntity> listResumes(Long userId, Long positionId, String query,
                                                          PagingInfo pagingInfo) throws Exception {
        if (StringUtils.isBlank(query)) {
            return listResumes(userId, positionId, pagingInfo);
        }

        List<ResumeContentQueryItem> resumeContentQueryItems =
                bizHumanResourceResumeContentService.searchByResumeContent(query, positionId);
        if (CollectionUtils.isEmpty(resumeContentQueryItems)) {
            return Collections.emptyList();
        }
        List<Long> ids =
                resumeContentQueryItems.stream().map(ResumeContentQueryItem::getResumeId).collect(Collectors.toList());

        ResumeQueryCondition condition = new ResumeQueryCondition();
        condition.setIds(ids);
        condition.setPositionId(positionId);
        condition.setMemberId(userId);
        List<ResumeQueryItem> resumeQueryItems = bizHumanResourceResumeService.resumeQuery(condition, pagingInfo);
        return resumeQueryItems.stream().map(BizHumanResourceResumeConvert::resumeQueryItemToEntity)
                .collect(Collectors.toList());
    }

    @Override
    public BizHumanResourceResumeEntity getResumeDetail(Long userId, Long resumeId) throws Exception {
        BizHumanResourceResumeEntity bizHumanResourceResumeEntity = new BizHumanResourceResumeEntity();
        bizHumanResourceResumeEntity.setId(resumeId);
        bizHumanResourceResumeEntity.setMemberId(userId);
        bizHumanResourceResumeEntity.setIsDeleted(CommonConstant.IsDeleted.N);
        List<BizHumanResourceResumeEntity> entities =
                bizHumanResourceResumeService.findByExample(bizHumanResourceResumeEntity, null);
        if (CollectionUtils.isEmpty(entities)) {
            return null;
        }
        return entities.get(0);
    }

    @Override
    public void deleteResumes(Long userId, Long... resumeIds) throws Exception {
        if (userId == null) {
            throw new BusinessException("用户未登录");
        }
        if (resumeIds == null || resumeIds.length == 0) {
            return;
        }

        String lock = "deleteResumeLock" + userId;
        synchronized (lock.intern()) {
            for (Long resumeId : resumeIds) {
                bizHumanResourceResumeService.deletedById(resumeId);
            }
        }
    }

    @Override
    public List<BizHumanResourceResumeEntity> retrievalSearchResume(Long userId, String requirements, Long positionId,
                                                                    List<Long> resumeIds) {
        BizHumanResourcePositionEntity bizHumanResourcePositionEntity = bizHumanResourcePositionService.get(positionId);
        if (bizHumanResourcePositionEntity == null || !bizHumanResourcePositionEntity.getMemberId().equals(userId)) {
            throw new BusinessException("无岗位信息");
        }
        BizHumanResourceResumeEntity bizHumanResourceResumeEntity = new BizHumanResourceResumeEntity();
        bizHumanResourceResumeEntity.setPosition(positionId);
        bizHumanResourceResumeEntity.setIsDeleted(CommonConstant.IsDeleted.N);
        List<BizHumanResourceResumeEntity> entities =
                bizHumanResourceResumeService.findByExample(bizHumanResourceResumeEntity, null);
        if (CollectionUtils.isEmpty(entities)) {
            return Collections.emptyList();
        }

        // 获取与resumeIds的交集
        if (CollectionUtils.isNotEmpty(resumeIds)) {
            entities = entities.stream()
                    .filter(entity -> resumeIds.contains(entity.getId()))
                    .collect(Collectors.toList());
        }
        String resume = JsonUtils.serialize(entities);
        String position = JsonUtils.serialize(bizHumanResourcePositionEntity);
        List<Long> result = new ArrayList<>();
        try {
            Map<String, Object> inputs = new HashMap<>();
            inputs.put("resume", resume);
            inputs.put("position", position);
            inputs.put("requirements", requirements);

            // 创建聊天客户端
            DifyWorkflowClient client =
                    DifyClientFactory.createWorkflowClient(DIFY_BASE_URL, "app-xdQ9vgrG1DjhrWfXt7qRH0gS");
            // 创建聊天消息
            WorkflowRunRequest request = WorkflowRunRequest.builder()
                    .inputs(inputs)
                    .responseMode(ResponseMode.BLOCKING)
                    .user(DateUtils.getCurrDate())
                    .build();
            WorkflowRunResponse workflowRunResponse = client.runWorkflow(request);
            WorkflowRunResponse.WorkflowRunData data = workflowRunResponse.getData();
            Map<String, Object> outputs = data.getOutputs();
            if (outputs == null) {
                return Collections.emptyList();
            }
            List<Integer> output = (ArrayList<Integer>) outputs.get("output");
            if (output == null || CollectionUtils.isEmpty(output)) {
                return Collections.emptyList();
            }
            result = output.stream().map(Long::valueOf).collect(Collectors.toList());
            List<Long> finalResult = result;
            return entities.stream().filter(entity -> finalResult.contains(entity.getId())).collect(Collectors.toList());
        } catch (Exception e) {
            throw new BusinessException("");
        } finally {
            // 保存检索结果日志
            HumanResourceResumeNaturalLanguageRetrievalLogEntity humanResourceResumeNaturalLanguageRetrievalLogEntity =
                    new HumanResourceResumeNaturalLanguageRetrievalLogEntity();
            humanResourceResumeNaturalLanguageRetrievalLogEntity.setPostionId(positionId);
            humanResourceResumeNaturalLanguageRetrievalLogEntity.setPositionContent(position);
            humanResourceResumeNaturalLanguageRetrievalLogEntity.setResumeIds(CollectionUtils.isNotEmpty(result) ?
                    JsonUtils.serialize(result) : "[]");
            humanResourceResumeNaturalLanguageRetrievalLogEntity.setRetrievalContent(requirements);
            humanResourceResumeNaturalLanguageRetrievalLogService.save(humanResourceResumeNaturalLanguageRetrievalLogEntity);
        }
    }

    private void saveResumeContent(String fileURL, Long positionId, Long resumeId) throws Exception {
        File file = DocumentLoad.downloadURLDocument(fileURL);
        String resumeContent = DocumentLoad.documentToText(file);
        BizHumanResourceResumeContentEntity bizHumanResourceResumeContentEntity =
                new BizHumanResourceResumeContentEntity();
        bizHumanResourceResumeContentEntity.setResumeId(resumeId);
        bizHumanResourceResumeContentEntity.setPositionId(positionId);
        bizHumanResourceResumeContentEntity.setResumeContent(resumeContent);
        bizHumanResourceResumeContentService.save(bizHumanResourceResumeContentEntity);
        file.delete();
    }
}
