import * as vscode from 'vscode';
import { logInfo, logError } from '../../utils';
import { scanProject } from '../../features/projectArchitecture';
import type { ProjectProfile } from '../../features/projectChronicle';

/**
 * 프로젝트 아키텍처 문서 자동 갱신용 file-system watcher 의 lifecycle 관리.
 *
 * 의도: 사용자가 프로젝트 루트의 구조적 파일(src/**, package.json …) 을 만질 때
 * 아키텍처 문서가 자동으로 따라오게 하되,
 *   - 저장 burst 가 N 번의 regen 으로 폭주하지 않도록 6초 debounce
 *   - signature 해시가 같으면 실제 regen 은 skip (cheap path)
 *   - 같은 프로젝트가 이미 watch 중이면 재등록 안함 (idempotent)
 *
 * 옛 코드는 sidebarProvider 의 3개 state slot + 3개 메서드로 흩어져 있어,
 * 프로젝트 전환 / 비활성화 경로마다 정리 호출이 빠지면 watcher 가 leak 되거나
 * 두 개의 watcher 가 동시에 trigger 되는 미묘한 버그가 있었음.
 *
 * Manager 로 격리해 (a) lifecycle 단일 진입점, (b) 정리 책임 한 곳, (c)
 * dispose() 로 한 줄에 처리 가능.
 */
export class ArchitectureWatchManager {
    private watcher?: vscode.FileSystemWatcher;
    private debounceTimer?: NodeJS.Timeout;
    private watchedProjectId?: string;

    constructor(
        /** Debounce 만료 시 현재 활성 프로젝트 조회. provider 가 보유. */
        private readonly getActiveProject: () => ProjectProfile | null,
        /** Signature 변화가 있을 때 실제 regen 을 트리거. provider 가 보유. */
        private readonly refreshArchitecture: () => Promise<void>
    ) {}

    /**
     * 프로젝트 루트 watch 시작. 같은 projectId 가 이미 watch 중이면 noop.
     * autoUpdate=false 면 watchedProjectId 만 기록하고 실제 watcher 는 안 만든다
     * (다시 토글되면 정상 등록).
     */
    register(profile: ProjectProfile): void {
        if (!profile.projectRoot) return;
        if (this.watchedProjectId === profile.projectId && this.watcher) return;
        this.dispose();
        if (profile.architectureAutoUpdate === false) {
            this.watchedProjectId = profile.projectId;
            return;
        }
        const pattern = new vscode.RelativePattern(
            profile.projectRoot,
            '{package.json,tsconfig.json,README.md,src/**,media/**,docs/**,tests/**,core_py/**,lib/**,app/**}'
        );
        const watcher = vscode.workspace.createFileSystemWatcher(pattern);
        const onChange = () => this.scheduleRefresh();
        watcher.onDidCreate(onChange);
        watcher.onDidDelete(onChange);
        watcher.onDidChange(onChange);
        this.watcher = watcher;
        this.watchedProjectId = profile.projectId;
        logInfo('architecture: watcher registered.', { projectId: profile.projectId, root: profile.projectRoot });
    }

    /** Watcher + debounce timer 모두 정리. 프로젝트 전환/비활성화 시 호출. */
    dispose(): void {
        try { this.watcher?.dispose(); } catch { /* noop */ }
        this.watcher = undefined;
        if (this.debounceTimer) {
            clearTimeout(this.debounceTimer);
            this.debounceTimer = undefined;
        }
        this.watchedProjectId = undefined;
    }

    /**
     * 6 s debounce: 저장 burst 가 한 번의 regen 으로 합쳐지고, "updated 2m ago"
     * 뱃지가 여전히 믿을 만한 수준의 latency. signature 가 안 바뀌면 skip.
     */
    private scheduleRefresh(): void {
        if (this.debounceTimer) clearTimeout(this.debounceTimer);
        this.debounceTimer = setTimeout(async () => {
            const profile = this.getActiveProject();
            if (!profile || !profile.projectRoot || profile.architectureAutoUpdate === false) return;
            try {
                const scan = scanProject(profile.projectRoot, profile.projectName);
                if (scan.signature === profile.architectureLastScanSignature) return;
                await this.refreshArchitecture();
            } catch (e: any) {
                logError('architecture: auto-refresh failed.', { error: e?.message ?? String(e) });
            }
        }, 6000);
    }
}
