/**
 * ============================================================
 * MemoryManager — 5-Layer Cognitive Memory System (통합 진입점)
 * 
 * Astra의 모든 메모리 레이어를 통합 관리하는 중앙 매니저입니다.
 * 
 * ① Short-Term Memory   — 현재 대화 흐름 (FIFO)
 * ② Long-Term Memory     — 사용자 취향/규칙/결정
 * ③ Project Memory       — 프로젝트별 지식
 * ④ Procedural Memory    — 반복 작업 절차 (skill.md)
 * ⑤ Episodic Memory      — 과거 대화/결정 흐름
 * ============================================================
 */

import { BrainProfile } from '../config';
import { ShortTermMemory } from './ShortTermMemory';
import { LongTermMemory } from './LongTermMemory';
import { ProjectMemory } from './ProjectMemory';
import { ProceduralMemory } from './ProceduralMemory';
import { EpisodicMemory } from './EpisodicMemory';
import { MemoryExtractor } from './MemoryExtractor';
import { MemoryContextResult, MemoryConfig } from './types';
import {
    distillStaleEpisodes,
    shouldAutoDistill,
    recordDistillationRun,
    type DistillationArchiveMode,
} from './distillation';

export { ShortTermMemory } from './ShortTermMemory';
export { LongTermMemory } from './LongTermMemory';
export { ProjectMemory } from './ProjectMemory';
export { ProceduralMemory } from './ProceduralMemory';
export { EpisodicMemory } from './EpisodicMemory';
export { MemoryExtractor } from './MemoryExtractor';
export {
    distillStaleEpisodes,
    getLastDistillationRun,
    recordDistillationRun,
    shouldAutoDistill,
    DEFAULT_DISTILLATION_OPTIONS,
    type DistillationOptions,
    type DistillationReport,
    type DistillationMarker,
    type DistillationArchiveMode,
} from './distillation';
export * from './types';

export class MemoryManager {
    private shortTerm: ShortTermMemory;
    private longTerm: LongTermMemory;
    private procedural: ProceduralMemory;
    private episodic: EpisodicMemory;
    private extractor: MemoryExtractor;

    // Project Memory는 workspace별로 lazy-init
    private projectMemories = new Map<string, ProjectMemory>();

    private config: MemoryConfig;

    constructor(brainPath: string, config?: Partial<MemoryConfig>) {
        this.config = {
            enabled: true,
            shortTermLimit: 8,
            longTermMaxEntries: 100,
            episodicMaxEpisodes: 50,
            projectMemoryEnabled: true,
            proceduralMemoryEnabled: true,
            episodicMemoryEnabled: true,
            ...config
        };

        this.shortTerm = new ShortTermMemory();
        this.longTerm = new LongTermMemory(brainPath, this.config.longTermMaxEntries);
        this.procedural = new ProceduralMemory(brainPath);
        this.episodic = new EpisodicMemory(brainPath, this.config.episodicMaxEpisodes);
        this.extractor = new MemoryExtractor();
    }

    // ─── Context Building (핵심 API) ───

    /**
     * 프롬프트에 대해 모든 메모리 레이어에서 관련 컨텍스트를 수집합니다.
     * agent.ts의 buildMemoryContext()를 대체합니다.
     */
    public buildContext(
        currentPrompt: string,
        visibleHistory: Array<{ role: string; content: string }>,
        summarize: (text: string, maxLen: number) => string,
        workspacePath?: string
    ): string {
        if (!this.config.enabled) return '';

        const layers: MemoryContextResult[] = [];

        // ① Short-Term Memory
        const stm = this.shortTerm.buildContext(
            visibleHistory,
            this.config.shortTermLimit,
            summarize
        );
        if (stm) layers.push(stm);

        // ② Long-Term Memory
        const ltm = this.longTerm.buildContext(currentPrompt);
        if (ltm) layers.push(ltm);

        // ③ Project Memory
        if (this.config.projectMemoryEnabled && workspacePath) {
            const pm = this.getProjectMemory(workspacePath);
            const pmCtx = pm.buildContext(currentPrompt);
            if (pmCtx) layers.push(pmCtx);
        }

        // ④ Procedural Memory
        if (this.config.proceduralMemoryEnabled) {
            const proc = this.procedural.buildContext(currentPrompt);
            if (proc) layers.push(proc);
        }

        // ⑤ Episodic Memory
        if (this.config.episodicMemoryEnabled) {
            const ep = this.episodic.buildContext(currentPrompt);
            if (ep) layers.push(ep);
        }

        if (layers.length === 0) return '';

        // 관련도 순으로 정렬
        layers.sort((a, b) => b.relevance - a.relevance);

        const sections = layers
            .map((layer) => `### ${layer.label}\n${layer.content}`)
            .join('\n\n');

        return [
            '',
            '[MEMORY CONTEXT]',
            'Review this layered memory before preparing the answer. Use it only when relevant, and prefer the current user request when there is conflict.',
            sections
        ].join('\n');
    }

    // ─── Session Lifecycle ───

    /**
     * 세션 종료 시 호출하여 모든 메모리 레이어에 대해 추출을 수행합니다.
     */
    public onSessionEnd(
        sessionId: string,
        messages: Array<{ role: string; content: string; timestamp?: number }>,
        workspacePath?: string,
        distillationOpts?: {
            enabled: boolean;
            ageThresholdDays: number;
            intervalDays: number;
            archiveMode: DistillationArchiveMode;
            brainPath: string;
        },
    ): void {
        if (!this.config.enabled) return;

        const projectMemory = workspacePath
            ? this.getProjectMemory(workspacePath)
            : null;

        try {
            this.extractor.extractFromSession(
                sessionId,
                messages,
                this.longTerm,
                this.episodic,
                projectMemory,
                workspacePath
            );
        } catch { /* memory extraction should never break the main flow */ }

        // Persist long-term memory
        this.longTerm.save();

        // Auto-distillation — Distillation Loop 가 enabled 이고 interval 충족 시 stale
        // episodes 를 LongTerm digest 로 승급. 세션 종료 시점이 자연스러움 — 사용자가
        // 다음 세션 시작 전 한 번 cleanup.
        if (distillationOpts?.enabled && shouldAutoDistill(distillationOpts.brainPath, distillationOpts.intervalDays)) {
            try {
                const report = distillStaleEpisodes(this.episodic, this.longTerm, distillationOpts.brainPath, {
                    ageThresholdDays: distillationOpts.ageThresholdDays,
                    archiveMode: distillationOpts.archiveMode,
                });
                recordDistillationRun(distillationOpts.brainPath, report);
            } catch { /* distillation should never break session end */ }
        }
    }

    // ─── Direct Access (for UI & advanced features) ───

    public getLongTermMemory(): LongTermMemory {
        return this.longTerm;
    }

    public getProceduralMemory(): ProceduralMemory {
        return this.procedural;
    }

    public getEpisodicMemory(): EpisodicMemory {
        return this.episodic;
    }

    public getProjectMemory(workspacePath: string): ProjectMemory {
        if (!this.projectMemories.has(workspacePath)) {
            this.projectMemories.set(workspacePath, new ProjectMemory(workspacePath));
        }
        return this.projectMemories.get(workspacePath)!;
    }

    // ─── Config ───

    public updateConfig(partial: Partial<MemoryConfig>): void {
        Object.assign(this.config, partial);
    }

    public getConfig(): MemoryConfig {
        return { ...this.config };
    }
}
