/**
 * 고객사 / MRR / 갱신 트래커.
 *
 * 4인 기업의 수입 쪽 — `/runway` 가 통장과 burn 을 본다면, 여기는 *어디서 돈이 들어오나*.
 * Salesforce / HubSpot 같은 CRM 아닌 가벼운 event-sourced 로그.
 *
 * 저장 형식: JSON Lines (.jsonl) — append-only event log. 같은 customer 의 여러 이벤트를
 * 시간 순으로 재생하면 현재 상태 (MRR, 갱신일, 위험 등급) 가 나온다.
 *
 * 위치: `<workspace>/.astra/customers.jsonl`. 사람이 직접 편집 가능, grep / 백업 친화.
 * 민감 정보(고객사 이름, 매출) 포함되므로 외부로 안 보냄 — 로컬 only.
 */

import { createEventStore } from '../_shared/eventSourcedStore';

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

export type CustomerEventType = 'add' | 'note' | 'risk' | 'churn' | 'renew' | 'update';

export interface CustomerEvent {
    /** unique id — timestamp 기반. */
    id: string;
    /** ISO timestamp. */
    timestamp: string;
    /** 고객 식별자 — 소문자·trim 한 name 의 slug. 같은 customer 의 이벤트끼리 그룹. */
    customerId: string;
    /** 표시용 원본 이름 (가장 최근 이벤트의 이름 우선). */
    customerName: string;
    /** 이벤트 종류. */
    type: CustomerEventType;
    /** 월 매출 — add/renew/update 에서 사용. */
    mrr?: number;
    /** 갱신일 (YYYY-MM-DD) — add/renew/update. */
    renewalAt?: string;
    /** 요금제명 — 'pro' / 'enterprise' / 'starter' 등. */
    plan?: string;
    /** 자유 텍스트 — note / risk / churn 의 사유. */
    memo?: string;
}

export type CustomerStatus = 'active' | 'at-risk' | 'churned';

export interface CustomerState {
    customerId: string;
    customerName: string;
    mrr: number;
    plan?: string;
    renewalAt?: string;
    status: CustomerStatus;
    startedAt: string;
    lastEventAt: string;
    eventCount: number;
    notes: { timestamp: string; type: CustomerEventType; memo: string }[];
}

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

export const getCustomersFilePath = _store.getFilePath;
export const readEvents = _store.read;
export const appendEvent = _store.append;

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

/**
 * 이벤트 로그를 재생해 customerId 별 현재 상태 도출.
 *
 * - add: 신규 생성 (status=active, startedAt 설정)
 * - update / renew: mrr / renewalAt / plan 갱신, status=active 로 복귀 (renew 시)
 * - risk: status=at-risk, memo 누적
 * - churn: status=churned, mrr=0
 * - note: 노트 누적만, 상태 무변경
 */
export function computeCustomerStates(): Map<string, CustomerState> {
    const events = readEvents().slice().sort((a, b) => (a.timestamp || '').localeCompare(b.timestamp || ''));
    const states = new Map<string, CustomerState>();
    for (const e of events) {
        let s = states.get(e.customerId);
        if (!s) {
            if (e.type !== 'add') {
                // add 이벤트 없이 다른 이벤트가 먼저 와도 묵시적 생성 — 데이터 손상 방어.
                s = {
                    customerId: e.customerId,
                    customerName: e.customerName,
                    mrr: 0,
                    status: 'active',
                    startedAt: e.timestamp,
                    lastEventAt: e.timestamp,
                    eventCount: 0,
                    notes: [],
                };
                states.set(e.customerId, s);
            } else {
                s = {
                    customerId: e.customerId,
                    customerName: e.customerName,
                    mrr: e.mrr ?? 0,
                    plan: e.plan,
                    renewalAt: e.renewalAt,
                    status: 'active',
                    startedAt: e.timestamp,
                    lastEventAt: e.timestamp,
                    eventCount: 0,
                    notes: [],
                };
                states.set(e.customerId, s);
            }
        }
        s.customerName = e.customerName || s.customerName;
        s.lastEventAt = e.timestamp;
        s.eventCount += 1;

        switch (e.type) {
            case 'add':
                // 위에서 이미 처리 (첫 진입 분기) — 중복 add 면 update 처럼.
                if (e.mrr !== undefined) s.mrr = e.mrr;
                if (e.renewalAt) s.renewalAt = e.renewalAt;
                if (e.plan) s.plan = e.plan;
                break;
            case 'update':
            case 'renew':
                if (e.mrr !== undefined) s.mrr = e.mrr;
                if (e.renewalAt) s.renewalAt = e.renewalAt;
                if (e.plan) s.plan = e.plan;
                if (e.type === 'renew' && s.status !== 'churned') s.status = 'active';
                break;
            case 'risk':
                if (s.status !== 'churned') s.status = 'at-risk';
                if (e.memo) s.notes.push({ timestamp: e.timestamp, type: 'risk', memo: e.memo });
                break;
            case 'churn':
                s.status = 'churned';
                s.mrr = 0;
                if (e.memo) s.notes.push({ timestamp: e.timestamp, type: 'churn', memo: e.memo });
                break;
            case 'note':
                if (e.memo) s.notes.push({ timestamp: e.timestamp, type: 'note', memo: e.memo });
                break;
        }
    }
    return states;
}
