/**
 * 채용 파이프라인 트래커.
 *
 * 4인 → 5인 이상 확장 시점에 후보자가 여러 명, 여러 역할(개발/기획/디자인) 로
 * 들어오기 시작 — 노션·스프레드시트·이메일에 흩어진 정보를 한 명령으로 본다.
 *
 * Event-sourced (customersStore 와 동일 패턴) — append-only 이벤트 로그를
 * 재생해 후보자별 현재 단계 + 노트 누적 도출.
 *
 * 위치: `<workspace>/.astra/hire.jsonl`. 사람 직접 편집 가능.
 * 민감 정보(이름, 연봉, 거절 사유) 포함 — 로컬 only.
 */

import * as fs from 'fs';
import * as path from 'path';
import { createEventStore } from '../_shared/eventSourcedStore';

const STORE_REL_PATH = '.astra/hire.jsonl';

export type HireEventType = 'add' | 'stage' | 'note' | 'offer' | 'reject' | 'decline' | 'hire';

/**
 * 기본 파이프라인 단계. 사용자가 다른 단계명 지정 가능 — 그냥 문자열로 저장.
 * 표시 순서·정렬용으로 알려진 단계는 가중치 부여.
 */
export const KNOWN_STAGES = ['inbox', 'screened', 'interview', 'final', 'offer', 'accepted', 'hired', 'rejected', 'declined'] as const;
export type KnownStage = typeof KNOWN_STAGES[number];

export interface HireEvent {
    id: string;
    timestamp: string;
    candidateId: string;
    candidateName: string;
    role: string;
    type: HireEventType;
    /** stage 전환 시 새 단계. add 시 시작 단계 (기본 'inbox'). */
    stage?: string;
    /** offer 의 연봉 — KRW. */
    salary?: number;
    /** 입사 예정일 / 거절·이탈 사유. */
    memo?: string;
}

export interface CandidateState {
    candidateId: string;
    candidateName: string;
    role: string;
    stage: string;
    salary?: number;
    addedAt: string;
    lastEventAt: string;
    eventCount: number;
    notes: { timestamp: string; type: HireEventType; memo: string }[];
}

const _store = createEventStore<HireEvent>({
    relPath: STORE_REL_PATH,
    validate: (e): e is HireEvent => !!e
        && typeof (e as any).id === 'string'
        && typeof (e as any).candidateId === 'string'
        && typeof (e as any).type === 'string',
});

export const getHireFilePath = _store.getFilePath;
export const readHireEvents = _store.read;
export const appendHireEvent = _store.append;

export function candidateIdFromName(name: string): string {
    return name.toLowerCase().trim().replace(/\s+/g, '-').replace(/[^\w가-힣-]/g, '');
}

export function computeCandidateStates(): Map<string, CandidateState> {
    const events = readHireEvents().slice().sort((a, b) => (a.timestamp || '').localeCompare(b.timestamp || ''));
    const states = new Map<string, CandidateState>();
    for (const e of events) {
        let s = states.get(e.candidateId);
        if (!s) {
            s = {
                candidateId: e.candidateId,
                candidateName: e.candidateName,
                role: e.role || '',
                stage: e.stage || 'inbox',
                addedAt: e.timestamp,
                lastEventAt: e.timestamp,
                eventCount: 0,
                notes: [],
            };
            states.set(e.candidateId, s);
        }
        s.candidateName = e.candidateName || s.candidateName;
        s.role = e.role || s.role;
        s.lastEventAt = e.timestamp;
        s.eventCount += 1;

        switch (e.type) {
            case 'add':
                s.stage = e.stage || s.stage || 'inbox';
                break;
            case 'stage':
                if (e.stage) s.stage = e.stage;
                break;
            case 'offer':
                s.stage = 'offer';
                if (e.salary !== undefined) s.salary = e.salary;
                if (e.memo) s.notes.push({ timestamp: e.timestamp, type: 'offer', memo: e.memo });
                break;
            case 'hire':
                s.stage = 'hired';
                if (e.memo) s.notes.push({ timestamp: e.timestamp, type: 'hire', memo: e.memo });
                break;
            case 'reject':
                s.stage = 'rejected';
                if (e.memo) s.notes.push({ timestamp: e.timestamp, type: 'reject', memo: e.memo });
                break;
            case 'decline':
                s.stage = 'declined';
                if (e.memo) s.notes.push({ timestamp: e.timestamp, type: 'decline', memo: e.memo });
                break;
            case 'note':
                if (e.memo) s.notes.push({ timestamp: e.timestamp, type: 'note', memo: e.memo });
                break;
        }
    }
    return states;
}
