import type { TaskStatus } from '../features/tasks';

/**
 * Action-tag attribute 파서 3개 — pure / stateless / 테스트에서 직접 import.
 *
 * 공통 패턴: `key="value"` | `key='value'` | `key=bare` 모두 받아서 object 로.
 * LLM 이 어떤 따옴표 스타일로 emit 해도 통과시키기 위함 — 모델 prompt 에 "큰
 * 따옴표만 써" 같은 규칙을 강제하면 다른 환각이 늘어나서, 파서 쪽이 관대.
 *
 * `_` 접두는 "agent.ts 의 internal 이지만 테스트용으로만 export" 표시 — 외부
 * 사용처는 agent.ts 의 executeActions 와 tests/{taskStore,sheetsApi,calendarApi}.test.ts.
 * agent.ts 는 이 모듈을 re-export 해서 기존 import 경로 (`from '../src/agent'`) 유지.
 */

const ATTR_RE = /([\w-]+)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/g;

/**
 * <add_task> / <update_task> / <complete_task> 의 attribute 파서.
 * 모든 필드 optional 로 받고 caller 가 필수 체크. status 는 정규화 (in_progress, 등).
 */
export function _parseTaskAttrs(raw: string): {
    id?: string;
    title?: string;
    owner?: string;
    due?: string;
    notes?: string;
    status?: TaskStatus;
} {
    const out: any = {};
    const re = new RegExp(ATTR_RE.source, 'g');
    let m: RegExpExecArray | null;
    while ((m = re.exec(raw)) !== null) {
        const key = m[1].toLowerCase();
        const val = (m[2] ?? m[3] ?? m[4] ?? '').trim();
        if (!val) continue;
        switch (key) {
            case 'id': out.id = val; break;
            case 'title': out.title = val; break;
            case 'owner': out.owner = val; break;
            case 'due': out.due = val; break;
            case 'notes': out.notes = val; break;
            case 'status': {
                const v = val.toLowerCase().replace(/\s+/g, '_');
                if (v === 'in_progress' || v === 'inprogress' || v === 'progress') out.status = 'in_progress';
                else if (v === 'blocked' || v === 'block') out.status = 'blocked';
                else if (v === 'done' || v === 'completed' || v === 'closed') out.status = 'done';
                else out.status = 'open';
                break;
            }
        }
    }
    return out;
}

/**
 * <read_sheet> / <write_sheet> / <append_sheet> 의 attribute 문자열을 객체로 파싱.
 * spreadsheet_id / spreadsheetId / sheetId 모두 받는 — LLM 의 변형 emission 흡수.
 */
export function _parseSheetAttrs(raw: string): { spreadsheetId?: string; range?: string } {
    const out: { spreadsheetId?: string; range?: string } = {};
    const re = new RegExp(ATTR_RE.source, 'g');
    let m: RegExpExecArray | null;
    while ((m = re.exec(raw)) !== null) {
        const key = m[1].toLowerCase();
        const val = (m[2] ?? m[3] ?? m[4] ?? '').trim();
        if (!val) continue;
        if (key === 'spreadsheet_id' || key === 'spreadsheetid' || key === 'sheet_id' || key === 'sheetid') {
            out.spreadsheetId = val;
        } else if (key === 'range') {
            out.range = val;
        }
    }
    return out;
}

/**
 * <create_calendar_event ...> 의 attribute 문자열을 객체로 파싱.
 * 큰따옴표 / 작은따옴표 / 따옴표 없이 (공백·`>` 으로 종료) 모두 허용 — LLM 이 어떤
 * 스타일로 emit 해도 통과시키기 위함. 단위테스트 가능하도록 export.
 */
export function _parseCalEventAttrs(raw: string): {
    title?: string;
    start?: string;
    end?: string;
    duration?: number;
    location?: string;
    allDay?: boolean;
    /** 충돌 감지 무시하고 강행 — 사용자 확인 후에만 설정해야 함 (conflictCheck). */
    force?: boolean;
} {
    const out: any = {};
    // `-` 포함 키 (all-day) 지원 — 일부러 ATTR_RE 와 동일 패턴이지만 매번 fresh
    // regex 인스턴스를 만들어 lastIndex 공유 버그를 회피.
    const re = new RegExp(ATTR_RE.source, 'g');
    let m: RegExpExecArray | null;
    while ((m = re.exec(raw)) !== null) {
        const key = m[1].toLowerCase();
        const val = (m[2] ?? m[3] ?? m[4] ?? '').trim();
        if (!val) continue;
        switch (key) {
            case 'title': out.title = val; break;
            case 'start': out.start = val; break;
            case 'end': out.end = val; break;
            case 'duration': {
                const n = parseInt(val, 10);
                if (!Number.isNaN(n) && n > 0) out.duration = n;
                break;
            }
            case 'location': out.location = val; break;
            case 'all_day':
            case 'allday':
            case 'all-day':
                out.allDay = val === 'true' || val === '1' || val === 'yes';
                break;
            case 'force':
                out.force = val === 'true' || val === '1' || val === 'yes';
                break;
        }
    }
    return out;
}
