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

/**
 * Agent skill *.md 파일들과 그 부가 메타 (last selected, negativePrompt) 의
 * 영속 저장 layer. sidebarProvider 의 5개 file I/O 메서드 (`_getAgentsDir`,
 * `_sendAgentsList` 일부, `_createAgent` 일부, `_sendAgentContent` 일부,
 * `_updateAgent` 일부, `_deleteAgent` 일부) 에 흩어진 fs/globalState 호출을
 * 한 클래스로 묶음.
 *
 * Modal UI (showInputBox / showWarningMessage / openInEditorGroup) 와 webview
 * send 는 여전히 provider 가 담당 — 이 store 는 *파일 + globalState* 만 책임.
 *
 * 디렉토리 해상 우선순위:
 *   1) `g1nation.agentSkillsPath` 설정 (절대 경로, 없으면 mkdir, `~/...` expand)
 *   2) `<workspace>/.agent/skills` (없으면 mkdir)
 *   3) workspace 도 없으면 빈 문자열
 */
export class AgentSkillStore {
    private static readonly LAST_SELECTED_KEY = 'g1nation.lastAgentPath';

    constructor(private readonly context: vscode.ExtensionContext) {}

    /** Agent skill .md 들이 보관되는 디렉토리. 없으면 mkdir 시도. */
    getDir(): string {
        const configured = (vscode.workspace.getConfiguration('g1nation').get<string>('agentSkillsPath', '') || '').trim();
        const expanded = configured.startsWith('~/') || configured === '~'
            ? path.join(os.homedir(), configured.slice(1).replace(/^[\\/]/, ''))
            : configured;
        if (expanded && path.isAbsolute(expanded)) {
            if (!fs.existsSync(expanded)) {
                try { fs.mkdirSync(expanded, { recursive: true }); } catch { /* fall through */ }
            }
            if (fs.existsSync(expanded)) return expanded;
        }
        const workspaceFolders = vscode.workspace.workspaceFolders;
        if (workspaceFolders) {
            const localPath = path.join(workspaceFolders[0].uri.fsPath, '.agent', 'skills');
            if (!fs.existsSync(localPath)) {
                fs.mkdirSync(localPath, { recursive: true });
            }
            return localPath;
        }
        return '';
    }

    /** Agent skill .md 파일 목록 — { name, path }. 디렉토리 없으면 빈 배열. */
    list(): Array<{ name: string; path: string }> {
        const dir = this.getDir();
        if (!dir || !fs.existsSync(dir)) return [];
        const result: Array<{ name: string; path: string }> = [];
        for (const f of fs.readdirSync(dir)) {
            if (f.endsWith('.md')) {
                result.push({ name: f.replace('.md', ''), path: path.join(dir, f) });
            }
        }
        return result;
    }

    /** 마지막 선택 agent path — 없으면 'none'. */
    getLastSelectedPath(): string {
        return this.context.globalState.get<string>(AgentSkillStore.LAST_SELECTED_KEY, 'none');
    }

    /** 'none' 도 명시 저장 가능 (selection 해제 케이스). */
    async setLastSelectedPath(agentPath: string): Promise<void> {
        await this.context.globalState.update(AgentSkillStore.LAST_SELECTED_KEY, agentPath);
    }

    /** Negative prompt 는 agent 별로 따로 보관 — key = `negativePrompt:<path>`. */
    getNegativePrompt(agentPath: string): string {
        return this.context.globalState.get<string>(`negativePrompt:${agentPath}`, '');
    }

    async setNegativePrompt(agentPath: string, prompt: string): Promise<void> {
        await this.context.globalState.update(`negativePrompt:${agentPath}`, prompt);
    }

    /** Agent .md 본문 — 존재 안 하면 null. */
    readContent(agentPath: string): string | null {
        if (!fs.existsSync(agentPath)) return null;
        return fs.readFileSync(agentPath, 'utf8');
    }

    /** 본문 덮어쓰기. 에러는 호출자에게 throw — UI 에서 toast 띄우는 책임 위로 위임. */
    writeContent(agentPath: string, content: string): void {
        fs.writeFileSync(agentPath, content, 'utf8');
    }

    /**
     * 새 skill 파일 생성. name 을 sanitize 한 후 `<dir>/<safeName>.md` 에 템플릿 작성.
     * 이미 존재하면 그대로 둠 (idempotent — 사용자가 같은 이름 재진입해도 안전).
     * 디렉토리 해상 실패 / sanitize 결과 빈 문자열이면 null.
     */
    createNew(name: string): string | null {
        const safeName = name.trim().replace(/[^a-zA-Z0-9_\-ㄱ-힝가-힣]/g, '_');
        if (!safeName) return null;
        const dir = this.getDir();
        if (!dir) return null;
        const filePath = path.join(dir, `${safeName}.md`);
        if (!fs.existsSync(filePath)) {
            fs.writeFileSync(filePath, `# Agent Persona: ${safeName}\n\nAdd your instructions here...\n`, 'utf8');
        }
        return filePath;
    }

    /**
     * 삭제 (path traversal 가드 포함). 결과:
     *   - 'invalid' — agents 디렉토리 밖이거나 .md 가 아님
     *   - 'missing' — 이미 사라짐 (lastSelected 정리 필요)
     *   - 'deleted' — 정상 삭제
     * 에러 (perm 등) 는 throw — 호출자가 toast 처리.
     */
    delete(agentPath: string): 'invalid' | 'missing' | 'deleted' {
        const agentsDir = path.resolve(this.getDir());
        const targetPath = path.resolve(agentPath);
        if (!targetPath.startsWith(`${agentsDir}${path.sep}`) || path.extname(targetPath) !== '.md') {
            return 'invalid';
        }
        if (!fs.existsSync(targetPath)) {
            return 'missing';
        }
        fs.unlinkSync(targetPath);
        return 'deleted';
    }
}
