/**
 * Disk persistence for company-turn resume state.
 *
 * 각 turn의 sessionDir 안에 `_resume.json`을 두고, dispatcher가 매 의미 있는
 * 시점(plan 확정 / 각 stage 직후 / abort 시점)에 현재 상태를 덮어쓴다.
 * 재개 시점에는 이 파일을 읽어 `nextIndex` 부터 dispatch 재개.
 *
 * 쓰기 정책:
 *  - 같은 파일을 매번 덮어쓰지만, 부분쓰기로 깨지면 다음 재개가 실패하므로
 *    tmp → rename으로 원자성 보장 (POSIX rename은 atomic, Windows도 NTFS면 OK).
 *  - 실패는 로그만 남기고 turn 흐름은 절대 막지 않는다 (resume은 nice-to-have).
 *  - 자연 종료(completed/failed) 후에는 같은 파일에 status='completed'로 마킹.
 *    물리적으로 지우진 않음 — 향후 분석/감사 용도로 유지.
 */
import * as fs from 'fs';
import * as path from 'path';
import * as vscode from 'vscode';
import { logError, logInfo } from '../../utils';
import { resolveCompanyBase } from './sessionStore';
import { CompanyResumeState } from './types';

const RESUME_FILE = '_resume.json';

/**
 * Write the resume state atomically. tmp 파일에 쓰고 rename으로 덮어써서 부분
 * 쓰기 도중 크래시가 나도 기존 _resume.json은 일관된 상태로 남도록 한다.
 *
 * 반환: 성공 여부. 실패하면 호출자가 사용자에게 알릴 수 있게 boolean 으로 surface.
 * 옛 버전은 silent 로 logError 만 남겨서 사용자는 *resume turn 이 사라진 줄도 모름*.
 */
export function writeResumeState(sessionDir: string, state: CompanyResumeState): { ok: true } | { ok: false; reason: string } {
    const target = path.join(sessionDir, RESUME_FILE);
    const tmp = target + '.tmp';
    try {
        fs.mkdirSync(sessionDir, { recursive: true });
        fs.writeFileSync(tmp, JSON.stringify(state, null, 2), 'utf8');
        fs.renameSync(tmp, target);
        return { ok: true };
    } catch (e: any) {
        const reason = e?.message ?? String(e);
        logError('company.resumeStore: write failed.', {
            sessionDir: path.basename(sessionDir),
            error: reason,
        });
        return { ok: false, reason };
    }
}

/**
 * 해당 세션의 resume 상태를 읽어온다. 파일이 없거나 파싱 실패 시 null.
 * 호환성 검사: version이 일치하지 않으면 안전하게 거부 (재개 불가로 취급).
 */
export function readResumeState(sessionDir: string): CompanyResumeState | null {
    const p = path.join(sessionDir, RESUME_FILE);
    if (!fs.existsSync(p)) return null;
    try {
        const raw = fs.readFileSync(p, 'utf8');
        const parsed = JSON.parse(raw) as CompanyResumeState;
        if (!parsed || parsed.version !== 1) return null;
        if (!parsed.timestamp || !parsed.userPrompt || !parsed.plan) return null;
        if (!Array.isArray(parsed.agentOutputs)) return null;
        if (typeof parsed.nextIndex !== 'number' || parsed.nextIndex < 0) return null;
        if (!['in-progress', 'aborted', 'completed', 'failed'].includes(parsed.status)) return null;
        return parsed;
    } catch (e: any) {
        logError('company.resumeStore: read failed.', {
            sessionDir: path.basename(sessionDir),
            error: e?.message ?? String(e),
        });
        return null;
    }
}

/**
 * 모든 세션 디렉터리를 스캔해서 "이어서 진행 가능한" 것만 골라낸다.
 * 기준:
 *   - `_resume.json`이 존재
 *   - status === 'in-progress' || 'aborted' (자연 종료된 것 제외)
 *   - agentOutputs / nextIndex가 plan보다 짧음 (정말 미완)
 * 결과는 lastUpdatedAt 내림차순 (최근에 멈춘 것이 위로).
 */
export function listResumableSessions(context: vscode.ExtensionContext): CompanyResumeState[] {
    const base = path.join(resolveCompanyBase(context), 'sessions');
    if (!fs.existsSync(base)) return [];
    let entries: string[];
    try {
        entries = fs.readdirSync(base);
    } catch (e: any) {
        logError('company.resumeStore: list failed.', { error: e?.message ?? String(e) });
        return [];
    }
    const out: CompanyResumeState[] = [];
    for (const name of entries) {
        const dir = path.join(base, name);
        try {
            if (!fs.statSync(dir).isDirectory()) continue;
        } catch { continue; }
        const state = readResumeState(dir);
        if (!state) continue;
        if (state.status !== 'in-progress' && state.status !== 'aborted') continue;
        // sanity: nextIndex가 plan.tasks 길이 이상이면 사실상 완료 — skip.
        const totalTasks = state.plan?.tasks?.length ?? 0;
        if (totalTasks > 0 && state.nextIndex >= totalTasks) continue;
        out.push(state);
    }
    out.sort((a, b) => (b.lastUpdatedAt || '').localeCompare(a.lastUpdatedAt || ''));
    return out;
}

/**
 * 세션의 resume 상태를 마킹. 자연 종료 시 status='completed' (또는 'failed')로
 * 덮어써서 listResumable에서 자동으로 빠지게 한다.
 *
 * 파일을 물리적으로 지우지 않는 이유: 사용자의 _resume.json이 디버깅/감사
 * 경로에서 유용할 수 있고, 디스크 용량도 미미함 (~수 KB).
 */
export function markResumeStatus(
    sessionDir: string,
    status: CompanyResumeState['status'],
    abortReason?: string,
): void {
    const cur = readResumeState(sessionDir);
    if (!cur) return;
    const next: CompanyResumeState = {
        ...cur,
        status,
        abortReason: abortReason ?? cur.abortReason,
        lastUpdatedAt: new Date().toISOString(),
    };
    writeResumeState(sessionDir, next);
    logInfo('company.resumeStore: status updated.', {
        sessionDir: path.basename(sessionDir),
        status,
    });
}

/** 절대 세션 디렉터리 경로 헬퍼 — 재개 진입점이 timestamp만 받았을 때 사용. */
export function resolveSessionDir(context: vscode.ExtensionContext, timestamp: string): string {
    return path.join(resolveCompanyBase(context), 'sessions', timestamp);
}
