/**
 * Generic event-sourced store — append-only `.jsonl` 파일 1개를 읽고/쓰는 공통 기반.
 *
 * 배경: customers, hire, runway, feedback 4개 store 가 같은 패턴 4번 반복
 * (getXFilePath / readX / appendX / countX) — byte-for-byte 중복 ~240줄.
 * 한 곳에서 잡으면 BOM/인코딩 edge case 등 fix 도 한 번에 전파.
 *
 * 사용:
 *   const store = createEventStore<CustomerEvent>({
 *       relPath: '.astra/customers.jsonl',
 *       validate: (e) => typeof e.id === 'string' && typeof e.customerId === 'string',
 *   });
 *   store.read(); store.append(event); store.count(); store.getFilePath();
 *
 * 도메인별 로직 (computeStates 등) 은 그대로 도메인 파일에 남음 — 본 모듈은
 * I/O 만 추상화.
 */

import * as fs from 'fs';
import * as path from 'path';
import * as vscode from 'vscode';

export interface EventStoreOptions<E> {
    /** workspace root 기준 상대 경로. 예: '.astra/customers.jsonl'. */
    relPath: string;
    /** 파싱된 객체가 유효한 event 인지 판정. false 면 malformed 로 skip. */
    validate: (e: unknown) => e is E;
}

export interface EventStore<E> {
    getFilePath(): string | null;
    read(): E[];
    append(event: E): { ok: true; filePath: string } | { ok: false; error: string };
    count(): number;
}

export function createEventStore<E>(opts: EventStoreOptions<E>): EventStore<E> {
    function getFilePath(): string | null {
        const folders = vscode.workspace.workspaceFolders;
        if (!folders || folders.length === 0) return null;
        return path.join(folders[0].uri.fsPath, opts.relPath);
    }

    function read(): E[] {
        const fp = getFilePath();
        if (!fp || !fs.existsSync(fp)) return [];
        const out: E[] = [];
        let content = '';
        try { content = fs.readFileSync(fp, 'utf-8'); } catch { return []; }
        for (const line of content.split('\n')) {
            const trimmed = line.trim();
            if (!trimmed) continue;
            try {
                const parsed = JSON.parse(trimmed);
                if (opts.validate(parsed)) out.push(parsed);
            } catch { /* skip malformed — append-only 라 손상 1줄이 전체 무력화하면 안 됨 */ }
        }
        return out;
    }

    function append(event: E): { ok: true; filePath: string } | { ok: false; error: string } {
        const fp = getFilePath();
        if (!fp) return { ok: false, error: '워크스페이스 폴더가 없어 저장 불가. VS Code 에서 폴더를 열어 주세요.' };
        try {
            fs.mkdirSync(path.dirname(fp), { recursive: true });
            fs.appendFileSync(fp, JSON.stringify(event) + '\n', 'utf-8');
            return { ok: true, filePath: fp };
        } catch (e: any) {
            return { ok: false, error: e?.message || String(e) };
        }
    }

    function count(): number {
        const fp = getFilePath();
        if (!fp || !fs.existsSync(fp)) return 0;
        try {
            const content = fs.readFileSync(fp, 'utf-8');
            return content.split('\n').filter((l) => l.trim()).length;
        } catch { return 0; }
    }

    return { getFilePath, read, append, count };
}
