package tech.easyflow.admin.service.agent;

import com.mybatisflex.core.query.QueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import tech.easyflow.admin.dto.chatworkspace.*;
import tech.easyflow.agent.entity.Agent;
import tech.easyflow.agent.runtime.AgentRuntimeStateCleanupService;
import tech.easyflow.agent.runtime.composer.AgentComposerDraftService;
import tech.easyflow.agent.runtime.media.AgentMediaService;
import tech.easyflow.agent.service.AgentService;
import tech.easyflow.ai.entity.DocumentCollection;
import tech.easyflow.ai.enums.PublishStatus;
import tech.easyflow.ai.service.DocumentCollectionService;
import tech.easyflow.chatlog.domain.command.ChatSessionUpsertCommand;
import tech.easyflow.chatlog.domain.dto.*;
import tech.easyflow.chatlog.domain.query.ChatPageQuery;
import tech.easyflow.chatlog.service.ChatSessionCommandService;
import tech.easyflow.chatlog.service.ChatSessionQueryService;
import tech.easyflow.chatlog.support.ChatJsonSupport;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.system.enums.CategoryResourceType;
import tech.easyflow.system.enums.ResourceAction;
import tech.easyflow.system.service.ResourceAccessService;

import java.math.BigInteger;
import java.util.*;

/**
 * Agent 管理端会话服务。
 */
@Service
public class AgentSessionService {

    private static final String ASSISTANT_CODE = "AGENT";

    private final ChatSessionQueryService chatSessionQueryService;
    private final ChatSessionCommandService chatSessionCommandService;
    private final AgentService agentService;
    private final DocumentCollectionService documentCollectionService;
    private final ResourceAccessService resourceAccessService;
    private final AgentRuntimeStateCleanupService agentRuntimeStateCleanupService;
    private final AgentMediaService agentMediaService;
    private final AgentComposerDraftService agentComposerDraftService;
    private final ChatJsonSupport chatJsonSupport;

    /**
     * 创建 Agent 管理端会话服务。
     *
     * @param chatSessionQueryService 聊天会话查询服务
     * @param chatSessionCommandService 聊天会话命令服务
     * @param agentService Agent 服务
     * @param documentCollectionService 知识库服务
     * @param resourceAccessService 资源访问服务
     * @param agentRuntimeStateCleanupService Agent 运行态清理服务
     * @param agentMediaService Agent 媒体服务
     * @param agentComposerDraftService Agent 输入草稿服务
     * @param chatJsonSupport 聊天 JSON 工具
     */
    public AgentSessionService(ChatSessionQueryService chatSessionQueryService,
                               ChatSessionCommandService chatSessionCommandService,
                               AgentService agentService,
                               DocumentCollectionService documentCollectionService,
                               ResourceAccessService resourceAccessService,
                               AgentRuntimeStateCleanupService agentRuntimeStateCleanupService,
                               AgentMediaService agentMediaService,
                               AgentComposerDraftService agentComposerDraftService,
                               ChatJsonSupport chatJsonSupport) {
        this.chatSessionQueryService = chatSessionQueryService;
        this.chatSessionCommandService = chatSessionCommandService;
        this.agentService = agentService;
        this.documentCollectionService = documentCollectionService;
        this.resourceAccessService = resourceAccessService;
        this.agentRuntimeStateCleanupService = agentRuntimeStateCleanupService;
        this.agentMediaService = agentMediaService;
        this.agentComposerDraftService = agentComposerDraftService;
        this.chatJsonSupport = chatJsonSupport;
    }

    /**
     * 查询当前用户的 Agent 会话分页。
     *
     * @param account 当前登录账号
     * @param agentId Agent ID
     * @param query 分页参数
     * @return Agent 会话分页
     */
    public ChatWorkspaceSessionPage queryCurrentUserSessions(LoginAccount account, BigInteger agentId, ChatPageQuery query) {
        ChatSessionPage page = chatSessionQueryService.pageSessions(account.getId(), agentId, ASSISTANT_CODE, query);
        Map<BigInteger, AgentAvailability> availabilityMap = resolveAgentAvailability(page.getRecords());
        ChatWorkspaceSessionPage result = new ChatWorkspaceSessionPage();
        result.setTotal(page.getTotal());
        result.setPageNumber(page.getPageNumber());
        result.setPageSize(page.getPageSize());
        List<ChatWorkspaceSessionView> records = new ArrayList<>();
        for (ChatSessionSummary summary : page.getRecords()) {
            records.add(toSessionView(summary, availabilityMap.get(summary.getAssistantId())));
        }
        result.setRecords(records);
        return result;
    }

    /**
     * 查询当前用户的 Agent 会话详情。
     *
     * @param account 当前登录账号
     * @param sessionId 会话 ID
     * @return Agent 会话详情
     */
    public ChatWorkspaceSessionDetailView getCurrentUserSession(LoginAccount account, BigInteger sessionId) {
        ChatSessionSummary summary = requireUserAgentSession(account, sessionId);
        AgentAvailability availability = resolveAgentAvailability(List.of(summary)).get(summary.getAssistantId());
        ChatWorkspaceSessionDetailView detail = new ChatWorkspaceSessionDetailView();
        fillSessionView(detail, summary, availability);
        Agent displayAgent = availability == null ? null : availability.displayAgent();
        detail.setAssistant(toAssistantView(displayAgent, summary));
        detail.setBoundKnowledges(resolveBoundKnowledges(displayAgent));
        ExtraKnowledgeResolution extraKnowledgeResolution = resolveExtraKnowledges(summary);
        detail.setExtraKnowledges(extraKnowledgeResolution.validKnowledges());
        detail.setRemovedExtraKnowledgeNames(extraKnowledgeResolution.removedNames());
        if (extraKnowledgeResolution.shouldSync()) {
            syncSessionExtraKnowledges(summary, extraKnowledgeResolution.validKnowledgeIds(), account.getId());
        }
        return detail;
    }

    /**
     * 查询当前用户的 Agent 会话消息。
     *
     * @param account 当前登录账号
     * @param sessionId 会话 ID
     * @param query 分页参数
     * @return 消息分页
     */
    public ChatHistoryPage queryCurrentUserMessages(LoginAccount account, BigInteger sessionId, ChatPageQuery query) {
        requireUserAgentSession(account, sessionId);
        return chatSessionQueryService.pageMainlineMessages(sessionId, query);
    }

    /**
     * 查询当前用户的 Agent 完整会话。
     *
     * @param account 当前登录账号
     * @param sessionId 会话 ID
     * @return 完整会话
     */
    public ChatWorkspaceConversationView getCurrentUserConversation(LoginAccount account, BigInteger sessionId) {
        requireUserAgentSession(account, sessionId);
        List<ChatMessageRecord> records = chatSessionQueryService.listMainlineMessages(sessionId);
        ChatWorkspaceConversationView view = new ChatWorkspaceConversationView();
        view.setRecords(records);
        view.setTotal(records.size());
        return view;
    }

    /**
     * 重命名当前用户的 Agent 会话。
     *
     * @param account 当前登录账号
     * @param sessionId 会话 ID
     * @param title 新标题
     */
    public void renameCurrentUserSession(LoginAccount account, BigInteger sessionId, String title) {
        if (!StringUtils.hasText(title)) {
            throw new BusinessException("标题不能为空");
        }
        requireUserAgentSession(account, sessionId);
        chatSessionCommandService.renameSession(sessionId, account.getId(), title.trim(), account.getId());
    }

    /**
     * 保存当前用户 Agent 会话的临时知识库。
     *
     * @param account 当前登录账号
     * @param sessionId 会话 ID
     * @param knowledgeIds 临时知识库 ID
     * @return 更新后的会话详情
     */
    public ChatWorkspaceSessionDetailView saveCurrentUserExtraKnowledges(LoginAccount account,
                                                                         BigInteger sessionId,
                                                                         List<BigInteger> knowledgeIds) {
        ChatSessionSummary summary = requireUserAgentSession(account, sessionId);
        ExtraKnowledgeResolution resolution = resolveVisibleKnowledgeViews(normalizeExtraKnowledgeIds(knowledgeIds));
        if (!resolution.removedNames().isEmpty()) {
            throw new BusinessException("所选知识库已失效或无权限使用");
        }
        syncSessionExtraKnowledges(summary, resolution.validKnowledgeIds(), account.getId());
        return getCurrentUserSession(account, sessionId);
    }

    /**
     * 删除当前用户的 Agent 会话。
     *
     * @param account 当前登录账号
     * @param sessionId 会话 ID
     */
    public void deleteCurrentUserSession(LoginAccount account, BigInteger sessionId) {
        ChatSessionSummary summary = chatSessionQueryService.getSessionSummary(sessionId);
        if (summary == null || Integer.valueOf(1).equals(summary.getIsDeleted())) {
            // 上一次删除可能已写入删除标记但媒体清理失败，重试时继续清理当前用户目录。
            deleteComposerDraft(summary, account, sessionId);
            agentMediaService.deleteFormalSession(sessionId.toString(), account);
            return;
        }
        requireUserAgentSession(account, summary);
        agentRuntimeStateCleanupService.clearChatSession(sessionId, account.getId());
        chatSessionCommandService.deleteSession(sessionId, account.getId(), account.getId());
        deleteComposerDraft(summary, account, sessionId);
        agentMediaService.deleteFormalSession(sessionId.toString(), account);
    }

    /**
     * 删除会话对应的未发送草稿和临时图片。
     *
     * @param summary 会话摘要
     * @param account 当前登录账号
     * @param sessionId 会话 ID
     */
    private void deleteComposerDraft(ChatSessionSummary summary, LoginAccount account, BigInteger sessionId) {
        if (summary == null || summary.getAssistantId() == null) {
            return;
        }
        agentComposerDraftService.delete(AgentMediaService.MODE_FORMAL,
                summary.getAssistantId().toString(), sessionId.toString(), account);
    }

    private ChatSessionSummary requireUserAgentSession(LoginAccount account, BigInteger sessionId) {
        ChatSessionSummary summary = chatSessionQueryService.getSessionSummary(sessionId);
        if (summary == null || Integer.valueOf(1).equals(summary.getIsDeleted())) {
            throw new BusinessException("Agent 会话不存在");
        }
        requireUserAgentSession(account, summary);
        return summary;
    }

    /**
     * 校验会话属于当前用户且类型为 Agent。
     *
     * @param account 当前登录账号
     * @param summary 会话摘要
     * @throws BusinessException 会话类型不匹配或不属于当前用户时抛出
     */
    private void requireUserAgentSession(LoginAccount account, ChatSessionSummary summary) {
        if (!ASSISTANT_CODE.equals(summary.getAssistantCode())) {
            throw new BusinessException("Agent 会话不存在");
        }
        if (!Objects.equals(summary.getUserId(), account.getId())) {
            throw new BusinessException("无权访问该 Agent 会话");
        }
    }

    private Map<BigInteger, AgentAvailability> resolveAgentAvailability(List<ChatSessionSummary> sessions) {
        Map<BigInteger, AgentAvailability> result = new LinkedHashMap<>();
        if (sessions == null || sessions.isEmpty()) {
            return result;
        }
        Set<BigInteger> agentIds = new LinkedHashSet<>();
        for (ChatSessionSummary session : sessions) {
            if (session != null && session.getAssistantId() != null) {
                agentIds.add(session.getAssistantId());
            }
        }
        if (agentIds.isEmpty()) {
            return result;
        }
        List<Agent> agents = agentService.list(QueryWrapper.create().in("id", agentIds));
        Map<BigInteger, Agent> agentMap = new LinkedHashMap<>();
        for (Agent agent : agents) {
            agentMap.put(agent.getId(), agent);
        }
        for (BigInteger agentId : agentIds) {
            Agent currentAgent = agentMap.get(agentId);
            if (currentAgent == null) {
                result.put(agentId, new AgentAvailability(false, ChatWorkspaceReadOnlyReason.ASSISTANT_DELETED, null));
                continue;
            }
            if (!resourceAccessService.canAccess(CategoryResourceType.AGENT, currentAgent, ResourceAction.USE)) {
                result.put(agentId, new AgentAvailability(false, ChatWorkspaceReadOnlyReason.NO_PERMISSION, null));
                continue;
            }
            boolean online = Integer.valueOf(1).equals(currentAgent.getStatus())
                    && PublishStatus.from(currentAgent.getPublishStatus()) == PublishStatus.PUBLISHED;
            result.put(agentId, new AgentAvailability(
                    online,
                    online ? null : ChatWorkspaceReadOnlyReason.ASSISTANT_OFFLINE,
                    toDisplayAgent(currentAgent)
            ));
        }
        return result;
    }

    private Agent toDisplayAgent(Agent currentAgent) {
        if (currentAgent.getPublishedSnapshotJson() != null && !currentAgent.getPublishedSnapshotJson().isEmpty()) {
            return agentService.fromSnapshot(currentAgent.getPublishedSnapshotJson());
        }
        return currentAgent;
    }

    private ChatWorkspaceSessionView toSessionView(ChatSessionSummary summary, AgentAvailability availability) {
        ChatWorkspaceSessionView view = new ChatWorkspaceSessionView();
        fillSessionView(view, summary, availability);
        return view;
    }

    private void fillSessionView(ChatWorkspaceSessionView view, ChatSessionSummary summary, AgentAvailability availability) {
        view.setSessionId(summary.getId());
        view.setAssistantId(summary.getAssistantId());
        view.setAssistantCode(summary.getAssistantCode());
        view.setAssistantName(summary.getAssistantName());
        view.setTitle(summary.getTitle());
        view.setLastMessagePreview(summary.getLastMessagePreview());
        view.setMessageCount(summary.getMessageCount());
        view.setAccessAt(summary.getAccessAt());
        view.setLastMessageAt(summary.getLastMessageAt());
        view.setContinuable(availability != null && availability.continuable());
        view.setReadOnlyReason(availability == null ? ChatWorkspaceReadOnlyReason.ASSISTANT_DELETED : availability.reason());
    }

    private ChatWorkspaceAssistantView toAssistantView(Agent agent, ChatSessionSummary summary) {
        ChatWorkspaceAssistantView view = new ChatWorkspaceAssistantView();
        if (agent != null) {
            view.setId(agent.getId());
            view.setAlias(agent.getId() == null ? null : agent.getId().toString());
            view.setTitle(agent.getName());
            view.setDescription(agent.getDescription());
            view.setIcon(agent.getAvatar());
            return view;
        }
        view.setId(summary == null ? null : summary.getAssistantId());
        view.setAlias(summary == null ? null : summary.getAssistantCode());
        view.setTitle(summary == null ? null : summary.getAssistantName());
        return view;
    }

    @SuppressWarnings("unchecked")
    private List<ChatWorkspaceKnowledgeView> resolveBoundKnowledges(Agent displayAgent) {
        if (displayAgent == null || displayAgent.getKnowledgeBindings() == null || displayAgent.getKnowledgeBindings().isEmpty()) {
            return List.of();
        }
        List<BigInteger> knowledgeIds = displayAgent.getKnowledgeBindings().stream()
                .map(binding -> binding.getKnowledgeId())
                .filter(Objects::nonNull)
                .toList();
        if (knowledgeIds.isEmpty()) {
            return List.of();
        }
        List<DocumentCollection> collections = documentCollectionService.listByIds(knowledgeIds);
        Map<BigInteger, DocumentCollection> collectionMap = new LinkedHashMap<>();
        for (DocumentCollection collection : collections) {
            collectionMap.put(collection.getId(), collection);
        }
        List<ChatWorkspaceKnowledgeView> views = new ArrayList<>();
        for (BigInteger knowledgeId : knowledgeIds) {
            DocumentCollection collection = collectionMap.get(knowledgeId);
            if (collection == null || PublishStatus.from(collection.getPublishStatus()) != PublishStatus.PUBLISHED) {
                continue;
            }
            views.add(toKnowledgeView(documentCollectionService.toPublishedView(collection)));
        }
        return views;
    }

    private ChatWorkspaceKnowledgeView toKnowledgeView(DocumentCollection collection) {
        ChatWorkspaceKnowledgeView view = new ChatWorkspaceKnowledgeView();
        view.setId(collection.getId());
        view.setAlias(collection.getAlias());
        view.setTitle(collection.getTitle());
        view.setDescription(collection.getDescription());
        view.setIcon(collection.getIcon());
        return view;
    }

    private ExtraKnowledgeResolution resolveExtraKnowledges(ChatSessionSummary summary) {
        ChatSessionExtPayload payload = chatJsonSupport.fromJson(summary.getExtJson(), ChatSessionExtPayload.class);
        List<BigInteger> extraKnowledgeIds = payload == null ? List.of() : payload.getExtraKnowledgeIds();
        return resolveVisibleKnowledgeViews(extraKnowledgeIds);
    }

    private ExtraKnowledgeResolution resolveVisibleKnowledgeViews(List<BigInteger> knowledgeIds) {
        if (knowledgeIds == null || knowledgeIds.isEmpty()) {
            return new ExtraKnowledgeResolution(List.of(), List.of(), List.of(), false);
        }
        List<BigInteger> normalizedIds = normalizeExtraKnowledgeIds(knowledgeIds);
        if (normalizedIds.isEmpty()) {
            return new ExtraKnowledgeResolution(List.of(), List.of(), List.of(), false);
        }
        List<DocumentCollection> collections = documentCollectionService.listByIds(normalizedIds);
        Map<BigInteger, DocumentCollection> collectionMap = new LinkedHashMap<>();
        for (DocumentCollection collection : collections) {
            collectionMap.put(collection.getId(), collection);
        }
        List<ChatWorkspaceKnowledgeView> validKnowledges = new ArrayList<>();
        List<BigInteger> validKnowledgeIds = new ArrayList<>();
        List<String> removedNames = new ArrayList<>();
        boolean changed = false;
        for (BigInteger knowledgeId : normalizedIds) {
            DocumentCollection current = collectionMap.get(knowledgeId);
            if (current == null) {
                removedNames.add("知识库#" + knowledgeId);
                changed = true;
                continue;
            }
            if (PublishStatus.from(current.getPublishStatus()) != PublishStatus.PUBLISHED) {
                removedNames.add(current.getTitle());
                changed = true;
                continue;
            }
            if (!resourceAccessService.canAccess(CategoryResourceType.KNOWLEDGE, current, ResourceAction.USE)) {
                removedNames.add(current.getTitle());
                changed = true;
                continue;
            }
            validKnowledges.add(toKnowledgeView(documentCollectionService.toPublishedView(current)));
            validKnowledgeIds.add(current.getId());
        }
        if (!Objects.equals(normalizedIds, validKnowledgeIds)) {
            changed = true;
        }
        return new ExtraKnowledgeResolution(validKnowledges, validKnowledgeIds, removedNames, changed);
    }

    private List<BigInteger> normalizeExtraKnowledgeIds(List<BigInteger> knowledgeIds) {
        if (knowledgeIds == null || knowledgeIds.isEmpty()) {
            return List.of();
        }
        List<BigInteger> normalizedIds = new ArrayList<>();
        for (BigInteger knowledgeId : knowledgeIds) {
            if (knowledgeId != null && !normalizedIds.contains(knowledgeId)) {
                normalizedIds.add(knowledgeId);
            }
        }
        if (normalizedIds.size() > 3) {
            throw new BusinessException("临时知识库最多选择 3 个");
        }
        return normalizedIds;
    }

    private void syncSessionExtraKnowledges(ChatSessionSummary summary, List<BigInteger> validKnowledgeIds, BigInteger operatorId) {
        ChatSessionExtPayload payload = new ChatSessionExtPayload();
        payload.setExtraKnowledgeIds(validKnowledgeIds);
        ChatSessionUpsertCommand command = new ChatSessionUpsertCommand();
        command.setSessionId(summary.getId());
        command.setTenantId(summary.getTenantId());
        command.setDeptId(summary.getDeptId());
        command.setUserId(summary.getUserId());
        command.setUserAccount(summary.getUserAccount());
        command.setAssistantId(summary.getAssistantId());
        command.setAssistantCode(summary.getAssistantCode());
        command.setAssistantName(summary.getAssistantName());
        command.setTitle(summary.getTitle());
        command.setExtJson(chatJsonSupport.toJson(payload));
        command.setOperatorId(operatorId);
        chatSessionCommandService.createOrTouchSession(command);
    }

    private record AgentAvailability(boolean continuable,
                                     ChatWorkspaceReadOnlyReason reason,
                                     Agent displayAgent) {
    }

    private record ExtraKnowledgeResolution(List<ChatWorkspaceKnowledgeView> validKnowledges,
                                            List<BigInteger> validKnowledgeIds,
                                            List<String> removedNames,
                                            boolean shouldSync) {
    }
}
