package com.ruoyi.web.modules.diagnosis.service.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.web.modules.diagnosis.domain.AiConsultOpenBody;
import com.ruoyi.web.modules.diagnosis.domain.AiConsultSendResult;
import com.ruoyi.web.modules.diagnosis.domain.AiConsultSessionView;
import com.ruoyi.web.modules.diagnosis.domain.BizConsultMessage;
import com.ruoyi.web.modules.diagnosis.domain.BizConsultSession;
import com.ruoyi.web.modules.diagnosis.domain.ConsultPushPayload;
import com.ruoyi.web.modules.diagnosis.domain.VetConsultSendBody;
import com.ruoyi.web.modules.diagnosis.domain.BizConsultUser;
import com.ruoyi.web.modules.diagnosis.mapper.BizConsultUserMapper;
import com.ruoyi.web.modules.diagnosis.mapper.BizConsultMessageMapper;
import com.ruoyi.web.modules.diagnosis.mapper.BizConsultSessionMapper;
import com.ruoyi.web.modules.diagnosis.service.IBizAiOnlineConsultService;
import com.ruoyi.web.modules.diagnosis.support.AiConsultConstants;
import com.ruoyi.web.modules.diagnosis.support.AiConsultValidation;
import com.ruoyi.web.modules.diagnosis.support.ConsultAiGateway;
import com.ruoyi.web.modules.diagnosis.support.ConsultMessagePreview;
import com.ruoyi.web.modules.diagnosis.support.ConsultPushService;
import com.ruoyi.web.modules.diagnosis.support.ConsultSessionProcessingLock;
import com.ruoyi.web.modules.diagnosis.support.ConsultSessionRules;
import com.ruoyi.web.modules.diagnosis.support.ConsultThreeMonthsWindow;
import com.ruoyi.web.modules.diagnosis.support.VetConsultValidation;

/**
 * AI 诊断（兽医、机构）服务实现。
 */
@Service
public class BizAiOnlineConsultServiceImpl implements IBizAiOnlineConsultService
{
    @Autowired
    private BizConsultSessionMapper bizConsultSessionMapper;

    @Autowired
    private BizConsultUserMapper bizConsultUserMapper;

    @Autowired
    private BizConsultMessageMapper bizConsultMessageMapper;

    @Autowired
    private ConsultAiGateway consultAiGateway;

    @Autowired
    private ConsultPushService consultPushService;

    @Autowired
    private ConsultSessionProcessingLock consultSessionProcessingLock;

    @Autowired
    private ISysUserService sysUserService;

    @Override
    public List<BizConsultSession> selectAiSessionList(BizConsultSession query, Long sysUserId)
    {
        if (sysUserId == null)
        {
            return new ArrayList<>();
        }
        BizConsultSession criteria = buildListCriteria(query, sysUserId);
        AiConsultValidation.validateListQuery(criteria, criteria.getSearchMode());
        List<BizConsultSession> list = bizConsultSessionMapper.selectAiSessionList(criteria);
        return list != null ? list : new ArrayList<>();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AiConsultSessionView createAiSession(Long askerUserId, String askerName, AiConsultOpenBody body)
    {
        if (askerUserId == null)
        {
            throw new ServiceException("请先登录");
        }
        Date now = new Date();
        BizConsultSession row = new BizConsultSession();
        row.setConsultType(ConsultSessionRules.CONSULT_TYPE_AI);
        row.setAskerUserId(askerUserId);
        row.setAskerName(resolveDisplayName(askerUserId, askerName));
        row.setReceiverUserId(null);
        row.setReceiverProviderId(null);
        row.setReceiverName(null);
        row.setSessionTitle(AiConsultConstants.SESSION_TITLE_NEW);
        row.setLastMessageTime(now);
        row.setLastMessagePreview(null);
        row.setVetVisible(ConsultSessionRules.VET_VISIBLE_YES);
        row.setCreateTime(now);
        row.setUpdateTime(now);
        bizConsultSessionMapper.insertBizConsultSession(row);
        ensureConsultUserOnNewSession(askerUserId, now);

        AiConsultSessionView view = new AiConsultSessionView();
        view.setId(row.getId());
        view.setConsultType(row.getConsultType());
        view.setAskerUserId(row.getAskerUserId());
        view.setAskerName(row.getAskerName());
        view.setSessionTitle(row.getSessionTitle());
        view.setLastMessageTime(row.getLastMessageTime());
        view.setVetVisible(row.getVetVisible());
        view.setCreateTime(row.getCreateTime());
        view.setDisclaimer(AiConsultConstants.DISCLAIMER);
        Integer category = body != null ? body.getCategory() : null;
        view.setPromptTemplate(AiConsultConstants.resolvePromptTemplate(category));
        return view;
    }

    @Override
    public List<BizConsultMessage> selectSessionMessages(Long sessionId, Long beforeId, Integer pageSize,
            Long askerUserId)
    {
        BizConsultSession session = loadOwnedSession(sessionId, askerUserId);
        int size = pageSize != null && pageSize > 0 ? pageSize : ConsultSessionRules.DEFAULT_MESSAGE_PAGE_SIZE;
        List<BizConsultMessage> batch = bizConsultMessageMapper.selectMessagesBeforeId(session.getId(), beforeId, size);
        if (batch == null || batch.isEmpty())
        {
            return new ArrayList<>();
        }
        List<BizConsultMessage> asc = new ArrayList<>(batch);
        Collections.reverse(asc);
        return asc;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AiConsultSendResult sendAiMessage(Long sessionId, VetConsultSendBody body, Long askerUserId, String askerName,
            String askerIp)
    {
        if (askerUserId == null)
        {
            throw new ServiceException("请先登录");
        }
        BizConsultSession session = loadOwnedSession(sessionId, askerUserId);
        if (!consultSessionProcessingLock.tryLock(session.getId()))
        {
            throw new ServiceException("AI 正在回复中，请稍候");
        }
        try
        {
            VetConsultValidation.validateSendBody(body);
            AiConsultValidation.validateAiCategory(body.getAiCategory());
            AiConsultValidation.validateCostTime(body.getCostTime());
            String displayName = resolveDisplayName(askerUserId, askerName);
            BizConsultMessage userMessage = persistUserMessage(session, body, askerUserId, displayName, askerIp);

            String aiText = resolveAiReplyText(body);
            if (StringUtils.isEmpty(aiText))
            {
                throw new ServiceException("AI 回复失败，请稍后重试");
            }

            BizConsultMessage aiMessage = persistAiMessage(session, aiText, body.getCostTime());
            updateSessionAfterAiReply(session, body, aiText);
            saveRealSessionIdIfPresent(session, body.getRealSessionId());

            AiConsultSendResult result = new AiConsultSendResult();
            result.setUserMessage(userMessage);
            result.setAiMessage(aiMessage);
            result.setRealSessionId(session.getRealSessionId());
            return result;
        }
        finally
        {
            consultSessionProcessingLock.unlock(session.getId());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int hideSession(Long sessionId, Long askerUserId)
    {
        if (sessionId == null || askerUserId == null)
        {
            throw new ServiceException("会话不存在或已删除");
        }
        int rows = bizConsultSessionMapper.updateSessionVisible(sessionId, askerUserId,
                ConsultSessionRules.CONSULT_TYPE_AI, ConsultSessionRules.VET_VISIBLE_NO);
        if (rows <= 0)
        {
            throw new ServiceException("会话不存在或已删除");
        }
        return rows;
    }

    private BizConsultMessage persistUserMessage(BizConsultSession session, VetConsultSendBody body, Long askerUserId,
            String askerName, String askerIp)
    {
        Date now = new Date();
        String content = StringUtils.trim(body.getContent());
        BizConsultMessage message = new BizConsultMessage();
        message.setSessionId(session.getId());
        message.setSenderRole(ConsultSessionRules.SENDER_ROLE_ASKER);
        message.setSenderUserId(askerUserId);
        message.setSenderName(askerName);
        message.setMsgType(body.getMsgType());
        message.setContent(content);
        message.setMediaDuration(body.getMediaDuration());
        message.setAiCategory(AiConsultValidation.normalizeAiCategory(body.getAiCategory()));
        message.setAskerIp(StringUtils.trim(askerIp));
        message.setSendTime(now);
        message.setCreateTime(now);
        bizConsultMessageMapper.insertBizConsultMessage(message);

        String preview = ConsultMessagePreview.build(body.getMsgType(), content);
        BizConsultSession patch = new BizConsultSession();
        patch.setId(session.getId());
        patch.setLastMessageTime(now);
        patch.setLastMessagePreview(preview);
        patch.setUpdateTime(now);
        updateSessionLastMessageAndUserLastUse(session, patch);

        consultPushService.publishNewMessage(buildPushPayload(message, session, preview, now));
        return message;
    }

    private BizConsultMessage persistAiMessage(BizConsultSession session, String aiText, Long costTime)
    {
        Date now = new Date();
        BizConsultMessage message = new BizConsultMessage();
        message.setSessionId(session.getId());
        message.setSenderRole(ConsultSessionRules.SENDER_ROLE_AI);
        message.setSenderUserId(0L);
        message.setSenderName(AiConsultConstants.AI_SENDER_NAME);
        message.setMsgType(ConsultSessionRules.MSG_TYPE_TEXT);
        message.setContent(aiText);
        message.setCostTime(AiConsultValidation.normalizeCostTime(costTime));
        message.setSendTime(now);
        message.setCreateTime(now);
        bizConsultMessageMapper.insertBizConsultMessage(message);

        String preview = ConsultMessagePreview.build(ConsultSessionRules.MSG_TYPE_TEXT, aiText);
        consultPushService.publishNewMessage(buildPushPayload(message, session, preview, now));
        return message;
    }

    private void updateSessionAfterAiReply(BizConsultSession session, VetConsultSendBody body, String aiText)
    {
        Date now = new Date();
        String preview = ConsultMessagePreview.build(ConsultSessionRules.MSG_TYPE_TEXT, aiText);
        BizConsultSession patch = new BizConsultSession();
        patch.setId(session.getId());
        patch.setLastMessageTime(now);
        patch.setLastMessagePreview(preview);
        patch.setUpdateTime(now);
        if (body.getMsgType() == ConsultSessionRules.MSG_TYPE_TEXT
                && (AiConsultConstants.SESSION_TITLE_NEW.equals(session.getSessionTitle())
                        || StringUtils.isEmpty(session.getSessionTitle())))
        {
            String userPreview = ConsultMessagePreview.build(body.getMsgType(), body.getContent());
            patch.setSessionTitle(userPreview);
        }
        updateSessionLastMessageAndUserLastUse(session, patch);
    }

    /**
     * 更新会话最后消息时间，并同步提问人在 AI 诊断用户表的末次使用时间。
     */
    private void updateSessionLastMessageAndUserLastUse(BizConsultSession session, BizConsultSession patch)
    {
        bizConsultSessionMapper.updateSessionLastMessage(patch);
        if (session != null && session.getAskerUserId() != null && patch.getLastMessageTime() != null)
        {
            bizConsultUserMapper.updateLastUseTime(session.getAskerUserId(), patch.getLastMessageTime());
        }
    }

    /**
     * 新建 AI 会话：用户表无记录则插入（首次/末次均为当前时间）。
     */
    private void ensureConsultUserOnNewSession(Long askerUserId, Date now)
    {
        if (askerUserId == null || now == null)
        {
            return;
        }
        if (bizConsultUserMapper.selectByUserId(askerUserId) != null)
        {
            return;
        }
        BizConsultUser row = new BizConsultUser();
        row.setUserId(askerUserId);
        row.setFirstUseTime(now);
        row.setLastUseTime(now);
        bizConsultUserMapper.insertBizConsultUser(row);
    }

    private String resolveAiReplyText(VetConsultSendBody body)
    {
        String clientReply = StringUtils.trim(body.getAiReplyContent());
        if (StringUtils.isNotEmpty(clientReply))
        {
            return clientReply;
        }
        try
        {
            return consultAiGateway.generateReply(body.getMsgType(), body.getContent(), body.getContent());
        }
        catch (Exception ex)
        {
            throw new ServiceException("AI 回复失败，请稍后重试");
        }
    }

    private ConsultPushPayload buildPushPayload(BizConsultMessage message, BizConsultSession session, String preview,
            Date lastTime)
    {
        ConsultPushPayload payload = new ConsultPushPayload();
        payload.setMessageId(message.getId());
        payload.setSessionId(session.getId());
        payload.setSenderRole(message.getSenderRole());
        payload.setSenderName(message.getSenderName());
        payload.setMsgType(message.getMsgType());
        payload.setContent(message.getContent());
        payload.setMediaDuration(message.getMediaDuration());
        payload.setSendTime(message.getSendTime());
        payload.setLastMessagePreview(preview);
        payload.setLastMessageTime(lastTime);
        payload.setVetUserId(null);
        payload.setAskerUserId(session.getAskerUserId());
        return payload;
    }

    private BizConsultSession buildListCriteria(BizConsultSession query, Long askerUserId)
    {
        BizConsultSession criteria = new BizConsultSession();
        criteria.setConsultType(ConsultSessionRules.CONSULT_TYPE_AI);
        criteria.setAskerUserId(askerUserId);
        criteria.setVetVisible(ConsultSessionRules.VET_VISIBLE_YES);
        if (query != null)
        {
            criteria.setSearchMode(query.getSearchMode());
            criteria.setContentKeyword(StringUtils.trim(query.getContentKeyword()));
        }
        if (!Boolean.TRUE.equals(criteria.getSearchMode()))
        {
            criteria.setThreeMonthsAgo(ConsultThreeMonthsWindow.calcThreeMonthsAgo(new Date()));
        }
        return criteria;
    }

    private BizConsultSession loadOwnedSession(Long sessionId, Long askerUserId)
    {
        if (sessionId == null || askerUserId == null)
        {
            throw new ServiceException("无权查看该会话");
        }
        BizConsultSession session = bizConsultSessionMapper.selectAiSessionById(sessionId);
        if (session == null)
        {
            throw new ServiceException("会话不存在或已删除");
        }
        if (session.getAskerUserId() == null || !session.getAskerUserId().equals(askerUserId))
        {
            throw new ServiceException("无权查看该会话");
        }
        if (session.getVetVisible() == null || session.getVetVisible() != ConsultSessionRules.VET_VISIBLE_YES)
        {
            throw new ServiceException("会话不存在或已删除");
        }
        return session;
    }

    private void saveRealSessionIdIfPresent(BizConsultSession session, String realSessionId)
    {
        String trimmed = StringUtils.trim(realSessionId);
        if (session == null || session.getId() == null || StringUtils.isEmpty(trimmed))
        {
            return;
        }
        bizConsultSessionMapper.updateRealSessionId(session.getId(), trimmed);
        session.setRealSessionId(trimmed);
    }

    private String resolveDisplayName(Long userId, String fallback)
    {
        if (StringUtils.isNotEmpty(fallback))
        {
            return fallback.trim();
        }
        try
        {
            com.ruoyi.common.core.domain.entity.SysUser user = sysUserService.selectUserById(userId);
            if (user != null && StringUtils.isNotEmpty(user.getNickName()))
            {
                return user.getNickName();
            }
            if (user != null && StringUtils.isNotEmpty(user.getUserName()))
            {
                return user.getUserName();
            }
        }
        catch (Exception ignored)
        {
            // 测试环境可能无用户表
        }
        return "用户" + userId;
    }
}
