/**
 * Task tracker — `.astra/company/_shared/tasks.md` 단일 파일.
 *
 * 설계 원칙:
 *   - 외부 DB 없이 *사람이 읽을 수 있는* 마크다운 테이블에 누적. git 으로 history 추적 가능.
 *   - 파싱은 regex 기반 (셀 구분자 `|`). 사용자가 손으로 편집해도 fault-tolerant.
 *   - 모든 task 는 안정적 id (t_001, t_002, ...) — agent 가 update/complete 시 식별자로 사용.
 *   - active / done 두 섹션. done 은 최근 N개만 보관 (오래된 건 archive).
 *
 * 파일 포맷:
 *
 *   # Tasks
 *
 *   ## Active
 *   | ID | Title | Owner | Due | Status | Notes |
 *   |---|---|---|---|---|---|
 *   | t_001 | 광고주 자료 정리 | @me | 2026-05-24T18:00 | in_progress | 자료 대기 |
 *   | t_002 | 디자인 리뷰 준비 | @planner | 2026-05-21T13:00 | open | |
 *
 *   ## Done (recent 10)
 *   | ID | Title | Owner | Completed |
 *   |---|---|---|---|
 *   | t_000 | 일정 셋업 | @me | 2026-05-20T10:00 |
 */

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

export type TaskStatus = 'open' | 'in_progress' | 'blocked' | 'done';

export interface Task {
    id: string;
    title: string;
    /** @me / @planner / @qa 같은 자유 형식. 정확한 agent id 와 무관해도 됨. */
    owner: string;
    /** ISO 'YYYY-MM-DDTHH:MM' 또는 빈 문자열. due 없는 task 도 허용. */
    due: string;
    status: TaskStatus;
    notes: string;
    /** done 으로 전환된 시각 ISO. status==='done' 일 때만 의미. */
    completedAt?: string;
}

const DONE_KEEP_RECENT = 10;

function _tasksPath(context: vscode.ExtensionContext): string {
    const ws = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
    if (ws) return path.join(ws, '.astra', 'company', '_shared', 'tasks.md');
    return path.join(context.globalStorageUri.fsPath, 'company', '_shared', 'tasks.md');
}

/** 전체 task store. active 와 done 분리. */
export interface TaskStore {
    active: Task[];
    done: Task[];
}

export function readTaskStore(context: vscode.ExtensionContext): TaskStore {
    const p = _tasksPath(context);
    try {
        if (!fs.existsSync(p)) return { active: [], done: [] };
        const md = fs.readFileSync(p, 'utf8');
        return parseTaskStore(md);
    } catch {
        return { active: [], done: [] };
    }
}

export function writeTaskStore(context: vscode.ExtensionContext, store: TaskStore): void {
    const p = _tasksPath(context);
    try {
        fs.mkdirSync(path.dirname(p), { recursive: true });
        fs.writeFileSync(p, renderTaskStore(store), 'utf8');
    } catch {
        // silent fail — caller 가 다음 read 에서 빈 store 받게 됨.
    }
}

// ────────────── parse ──────────────

export function parseTaskStore(md: string): TaskStore {
    const active: Task[] = [];
    const done: Task[] = [];
    let section: 'active' | 'done' | null = null;
    const lines = md.split(/\r?\n/);
    for (const line of lines) {
        if (/^##\s*Active/i.test(line)) { section = 'active'; continue; }
        if (/^##\s*Done/i.test(line)) { section = 'done'; continue; }
        if (!section) continue;
        if (!line.trim().startsWith('|')) continue;
        // header / separator 행 skip
        if (/^\|\s*ID\b/i.test(line)) continue;
        if (/^\|\s*[-:]+/.test(line)) continue;
        const cells = _parseRow(line);
        if (!cells || cells.length < 3) continue;
        if (section === 'active') {
            const [id, title, owner, due, status, notes] = cells;
            if (!id || !id.startsWith('t_')) continue;
            active.push({
                id,
                title: title ?? '',
                owner: owner ?? '',
                due: due ?? '',
                status: _normalizeStatus(status),
                notes: notes ?? '',
            });
        } else {
            const [id, title, owner, completedAt] = cells;
            if (!id || !id.startsWith('t_')) continue;
            done.push({
                id,
                title: title ?? '',
                owner: owner ?? '',
                due: '',
                status: 'done',
                notes: '',
                completedAt: completedAt ?? '',
            });
        }
    }
    return { active, done };
}

function _parseRow(line: string): string[] | null {
    const t = line.trim();
    if (!t.startsWith('|') || !t.endsWith('|')) return null;
    const inner = t.slice(1, -1);
    return inner.split('|').map((c) => c.trim().replace(/\\\|/g, '|'));
}

function _normalizeStatus(s: string | undefined): TaskStatus {
    const v = String(s ?? 'open').trim().toLowerCase().replace(/\s+/g, '_');
    if (v === 'in_progress' || v === 'inprogress' || v === 'progress') return 'in_progress';
    if (v === 'blocked' || v === 'block') return 'blocked';
    if (v === 'done' || v === 'completed' || v === 'closed') return 'done';
    return 'open';
}

// ────────────── render ──────────────

export function renderTaskStore(store: TaskStore): string {
    const lines: string[] = [
        '# Tasks',
        '',
        '## Active',
        '| ID | Title | Owner | Due | Status | Notes |',
        '|---|---|---|---|---|---|',
    ];
    for (const t of store.active) {
        lines.push(`| ${t.id} | ${_esc(t.title)} | ${_esc(t.owner)} | ${_esc(t.due)} | ${t.status} | ${_esc(t.notes)} |`);
    }
    if (store.active.length === 0) lines.push('_(no active tasks)_');
    lines.push('');
    lines.push(`## Done (recent ${DONE_KEEP_RECENT})`);
    lines.push('| ID | Title | Owner | Completed |');
    lines.push('|---|---|---|---|');
    const recentDone = store.done.slice(-DONE_KEEP_RECENT);
    for (const t of recentDone) {
        lines.push(`| ${t.id} | ${_esc(t.title)} | ${_esc(t.owner)} | ${_esc(t.completedAt ?? '')} |`);
    }
    if (recentDone.length === 0) lines.push('_(no completed tasks)_');
    return lines.join('\n') + '\n';
}

function _esc(s: string): string {
    return String(s ?? '').replace(/\|/g, '\\|').replace(/\n/g, ' ');
}

// ────────────── CRUD helpers ──────────────

/**
 * 새 task 추가. id 는 active+done 전체 max + 1.
 * 사용자가 같은 title 로 중복 요청해도 별개 task — dedup 책임은 agent.
 */
export function addTask(store: TaskStore, input: {
    title: string;
    owner?: string;
    due?: string;
    notes?: string;
    status?: TaskStatus;
}): Task {
    const allIds = [...store.active, ...store.done].map((t) => t.id);
    const max = allIds.reduce((acc, id) => {
        const m = id.match(/^t_(\d+)$/);
        if (!m) return acc;
        const n = parseInt(m[1], 10);
        return n > acc ? n : acc;
    }, 0);
    const id = `t_${String(max + 1).padStart(3, '0')}`;
    const task: Task = {
        id,
        title: input.title.trim(),
        owner: (input.owner ?? '').trim(),
        due: (input.due ?? '').trim(),
        status: input.status ?? 'open',
        notes: (input.notes ?? '').trim(),
    };
    store.active.push(task);
    return task;
}

/** id 로 task 찾아 patch 적용. 못 찾으면 null. */
export function updateTask(store: TaskStore, id: string, patch: Partial<Task>): Task | null {
    const idx = store.active.findIndex((t) => t.id === id);
    if (idx < 0) return null;
    const cur = store.active[idx];
    const next: Task = { ...cur, ...patch, id: cur.id };
    store.active[idx] = next;
    return next;
}

/**
 * task 를 done 으로 옮김. active 에서 빼고 done 에 push.
 * 못 찾으면 null. 이미 done 이었으면 active 에는 없으므로 동일.
 */
export function completeTask(store: TaskStore, id: string, completedAt?: string): Task | null {
    const idx = store.active.findIndex((t) => t.id === id);
    if (idx < 0) return null;
    const [t] = store.active.splice(idx, 1);
    const closed: Task = { ...t, status: 'done', completedAt: completedAt ?? new Date().toISOString().slice(0, 16) };
    store.done.push(closed);
    return closed;
}

/** 프롬프트 주입용 — active 만 짧은 마크다운으로. due 가 가까운 순. */
export function summarizeActiveTasks(store: TaskStore, max: number = 12): string {
    if (store.active.length === 0) return '';
    const sorted = [...store.active].sort((a, b) => {
        // due 있는 task 우선 (asc). 없는 건 뒤로.
        if (a.due && !b.due) return -1;
        if (!a.due && b.due) return 1;
        return (a.due || '').localeCompare(b.due || '');
    });
    const shown = sorted.slice(0, max);
    const lines = shown.map((t) => {
        const due = t.due ? ` · 마감 ${t.due}` : '';
        const owner = t.owner ? ` · ${t.owner}` : '';
        const status = t.status !== 'open' ? ` [${t.status}]` : '';
        const notes = t.notes ? ` — ${t.notes}` : '';
        return `- ${t.id}${status} ${t.title}${owner}${due}${notes}`;
    });
    if (sorted.length > max) lines.push(`- _(... ${sorted.length - max} more)_`);
    return lines.join('\n');
}
