package com.infoepoch.pms.agent.platform.chat.domain;

import com.infoepoch.pms.agent.common.utils.SnowFlake;
import com.infoepoch.pms.agent.platform.chatbot.domain.Chatbot;
import com.infoepoch.pms.agent.platform.shared.exception.BusinessException;
import com.infoepoch.pms.agent.platform.shared.response.ResultCode;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;

/**
 * 对话会话实体。
 * <p>
 * 代表一个用户与所选 Chatbot 的会话上下文，
 * 状态流转：active → completed（正常完成）或 abandoned（用户放弃）。
 * </p>
 */
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Session {

    /** 用户 ID 最大长度。 */
    private static final int USER_ID_MAX_LENGTH = 100;
    /** 会话标题最大长度。 */
    private static final int TITLE_MAX_LENGTH = 100;

    /**
     * 会话状态：活跃中。
     */
    public static final String STATUS_ACTIVE = "active";
    /**
     * 会话状态：已完成。
     */
    public static final String STATUS_COMPLETED = "completed";
    /**
     * 会话状态：已放弃。
     */
    public static final String STATUS_ABANDONED = "abandoned";

    private String id;

    /**
     * 用户标识，由调用方传入，不做格式约束。
     */
    private String userId;

    /**
     * 所属聊天机器人（多对一，懒加载）。
     */
    private Chatbot chatbot;

    /**
     * 所属聊天机器人id 多对一
     */
    private String chatBotId;

    /**
     * 会话状态：active / completed / abandoned。
     */
    private String status;

    /**
     * 会话标题，由 AI 在首条消息后异步生成，NULL 表示未生成。
     */
    private String title;

    /**
     * 当前会话活跃的上下文线程 ID。
     */
    private String activeThreadId;

    /**
     * 是否已标记“清除上下文待生效”。
     */
    private boolean contextResetPending;

    /**
     * 记录创建时间。
     */
    private LocalDateTime createdAt;

    /**
     * 记录最后更新时间。
     */
    private LocalDateTime updatedAt;

    /**
     * 仓储还原
     */
    public Session(String id, String userId, String chatBotId, String status, String title, String activeThreadId, boolean contextResetPending, LocalDateTime createdAt, LocalDateTime updatedAt) {
        this.id = id;
        this.userId = userId;
        this.chatBotId = chatBotId;
        this.status = status;
        this.title = title;
        this.activeThreadId = activeThreadId;
        this.contextResetPending = contextResetPending;
        this.createdAt = createdAt;
        this.updatedAt = updatedAt;
    }

    /**
     * 创建新会话。
     *
     * @param userId  用户标识，必填，最长 100 字符
     * @param chatbot 所属聊天机器人，不能为 null
     */
    public Session(String userId, Chatbot chatbot) {
        if (chatbot == null) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "聊天机器人不能为空");
        }
        LocalDateTime now = LocalDateTime.now();
        this.id = SnowFlake.instant().nextId().toString();
        this.userId = normalizeUserId(userId);
        this.chatbot = chatbot;
        this.chatBotId = chatbot.getId();
        this.status = STATUS_ACTIVE;
        this.activeThreadId = this.id;
        this.contextResetPending = false;
        this.createdAt = now;
        this.updatedAt = now;
    }

    public static Session restore(String id,
                                  String userId,
                                  Chatbot chatbot,
                                  String status,
                                  String title,
                                  String activeThreadId,
                                  boolean contextResetPending,
                                  LocalDateTime createdAt,
                                  LocalDateTime updatedAt) {
        Session session = new Session();
        session.id = id;
        session.userId = userId;
        session.chatbot = chatbot;
        session.chatBotId = chatbot == null ? null : chatbot.getId();
        session.status = status;
        session.title = title;
        session.activeThreadId = activeThreadId;
        session.contextResetPending = contextResetPending;
        session.createdAt = createdAt;
        session.updatedAt = updatedAt;
        return session;
    }

    public static Session restore(String id,
                                  String userId,
                                  Chatbot chatbot,
                                  String status,
                                  String title,
                                  LocalDateTime createdAt,
                                  LocalDateTime updatedAt) {
        return restore(id, userId, chatbot, status, title, id, false, createdAt, updatedAt);
    }

    public void setChatbot(Chatbot chatbot) {
        this.chatbot = chatbot;
        this.chatBotId = chatbot == null ? null : chatbot.getId();
    }

    /**
     * 将会话标记为已完成。
     *
     * @throws BusinessException SESSION_ALREADY_CLOSED 若会话不处于活跃状态
     */
    public void complete() {
        if (!STATUS_ACTIVE.equals(this.status)) {
            throw new BusinessException(ResultCode.SESSION_ALREADY_CLOSED,
                    "会话已关闭，无法完成");
        }
        this.status = STATUS_COMPLETED;
        this.updatedAt = LocalDateTime.now();
    }

    /**
     * 将会话标记为已放弃。
     *
     * @throws BusinessException SESSION_ALREADY_CLOSED 若会话不处于活跃状态
     */
    public void abandon() {
        if (!STATUS_ACTIVE.equals(this.status)) {
            throw new BusinessException(ResultCode.SESSION_ALREADY_CLOSED,
                    "会话已关闭，无法放弃");
        }
        this.status = STATUS_ABANDONED;
        this.updatedAt = LocalDateTime.now();
    }

    /**
     * 设置会话标题。
     *
     * @param title 标题，不能为空，最多 100 字符（超出会截断）
     */
    public void applyTitle(String title) {
        if (!StringUtils.hasText(title)) {
            return;
        }
        String normalized = title.trim();
        if (normalized.length() > TITLE_MAX_LENGTH) {
            normalized = normalized.substring(0, TITLE_MAX_LENGTH);
        }
        this.title = normalized;
        this.updatedAt = LocalDateTime.now();
    }

    public void markContextResetPending() {
        this.contextResetPending = true;
        this.updatedAt = LocalDateTime.now();
    }

    public void clearContextResetPending() {
        this.contextResetPending = false;
        this.updatedAt = LocalDateTime.now();
    }

    public void activateNextThread(String nextThreadId) {
        if (!StringUtils.hasText(nextThreadId)) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "新的上下文线程不能为空");
        }
        this.activeThreadId = nextThreadId.trim();
        this.contextResetPending = false;
        this.updatedAt = LocalDateTime.now();
    }

    /**
     * 规范化并校验用户 ID。
     *
     * @param userId 原始用户 ID
     * @return 规范化后的用户 ID
     */
    private String normalizeUserId(String userId) {
        if (!StringUtils.hasText(userId)) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "用户 ID 不能为空");
        }
        String normalized = userId.trim();
        if (normalized.length() > USER_ID_MAX_LENGTH) {
            throw new BusinessException(ResultCode.PARAM_ERROR,
                    "用户 ID 长度不能超过 " + USER_ID_MAX_LENGTH + " 个字符");
        }
        return normalized;
    }
}
