package com.gzzm.lobster.memory;

import com.gzzm.lobster.common.MemoryCategory;
import com.gzzm.lobster.common.MemoryStatus;
import net.cyan.thunwind.annotation.OQL;
import net.cyan.thunwind.annotation.OQLUpdate;
import net.cyan.thunwind.dao.GeneralDao;

import java.util.Date;
import java.util.List;

/**
 * PersonalMemoryDao —— 个人记忆持久化 / Personal memory persistence.
 *
 * <p>status 枚举 thunwind 默认存 smallint ordinal，OQL 用参数绑定不写字面量。
 */
public abstract class PersonalMemoryDao extends GeneralDao {

    @OQL("select m from PersonalMemory m where m.memoryId=:1")
    public abstract PersonalMemory getMemory(String memoryId) throws Exception;

    /**
     * 取"索引视图"——常驻 system 稳定前缀。
     * 按 createTime desc 取最新 N 条 active（截断老记忆）；service 层再反转成
     * createTime asc，让新记忆在渲染尾部 append——前缀稳定、利于 prompt-cache。
     * 调用方只会用到 memoryId / name / description / category（{@code content} 已标
     * {@code @Lazy}，访问时才加载）。
     */
    @OQL("select m from PersonalMemory m where m.userId=:1 and m.status=?2 order by m.createTime desc limit 0,:3")
    public abstract List<PersonalMemory> listIndex(String userId, MemoryStatus status, int limit) throws Exception;

    @OQL("select m from PersonalMemory m where m.userId=:1 and m.category=?2 and m.status=?3 order by m.createTime desc limit 0,:4")
    public abstract List<PersonalMemory> listByCategory(String userId, MemoryCategory category, MemoryStatus status, int limit) throws Exception;

    /**
     * 关键词检索：匹配 name / description / content 任一字段（中文二元组友好）。
     * 调用方先切 bigram，对每个 token 分别用 {@code %tok%} 查一次再 OR 合并。
     */
    @OQL("select m from PersonalMemory m where m.userId=:1 and m.status=?2"
            + " and (m.name like ?3 or m.description like ?3 or m.content like ?3)"
            + " order by m.updateTime desc limit 0,:4")
    public abstract List<PersonalMemory> searchSimple(String userId, MemoryStatus status, String pattern, int limit) throws Exception;

    /** 按 name 精确查（写入去重用）。 */
    @OQL("select m from PersonalMemory m where m.userId=:1 and m.name=?2 and m.status=?3 limit 0,1")
    public abstract PersonalMemory findByName(String userId, String name, MemoryStatus status) throws Exception;

    @OQLUpdate("update PersonalMemory set status=?1, updateTime=?2 where memoryId=?3 and userId=?4")
    public abstract int suppress(MemoryStatus status, Date now, String memoryId, String userId) throws Exception;

    @OQLUpdate("update PersonalMemory set description=?1, content=?2, updateTime=?3 where memoryId=?4 and userId=?5")
    public abstract int updateBody(String description, String content, Date now, String memoryId, String userId) throws Exception;

    @OQLUpdate("update PersonalMemory set lastAccessedAt=?1 where memoryId=?2")
    public abstract int touch(Date now, String memoryId) throws Exception;
}
