import type { Clock, Fs } from './io' import { readJson, writeJson } from './io' export interface Todo { id: number title: string done: boolean /** 承諾事項:助理答應記住的事 */ promise: boolean dueAt?: number createdAt: number doneAt?: number /** 已提醒過,避免重複 */ reminded?: boolean } export interface TodoList { add(title: string, opts?: { promise?: boolean; dueAt?: number }): Promise complete(id: number): Promise list(opts?: { all?: boolean }): Promise /** 角色行顯示的待辦數(未完成) */ open(): Promise /** 取出到期且尚未提醒的項目,並標記為已提醒 */ due(): Promise } export function createTodos(fs: Fs, clock: Clock, path: string): TodoList { const load = () => readJson(fs, path, []) const save = (t: Todo[]) => writeJson(fs, path, t) return { async add(title, opts = {}) { const all = await load() const t: Todo = { id: all.reduce((m, x) => Math.max(m, x.id), 0) + 1, title: title.trim(), done: false, promise: !!opts.promise, dueAt: opts.dueAt, createdAt: clock(), } all.push(t) await save(all) return t }, async complete(id) { const all = await load() const t = all.find(x => x.id === id) if (!t || t.done) return t ?? null t.done = true t.doneAt = clock() await save(all) return t }, async list(opts = {}) { const all = await load() return opts.all ? all : all.filter(t => !t.done) }, async open() { return (await load()).filter(t => !t.done).length }, async due() { const all = await load() const now = clock() const hit = all.filter(t => !t.done && !t.reminded && t.dueAt !== undefined && t.dueAt <= now) if (hit.length) { for (const t of hit) t.reminded = true await save(all) } return hit }, } }