type State = "IDLE" | "WORKING" | "PAUSED" | "ABSENT";

export type SpanStatus = "factual" | "submitted" | "approved" | "rejected";

export type DerivedSpan = {
    type: "work" | "pause" | "vacation" | "sick" | "overtime_compensation";
    startedAt: Date;
    endedAt: Date | null;
    sourceEventIds: string[];
    status: SpanStatus;
    statusActorId?: string;
    payload?: Record<string, any> | null;
    description?: string;
};

type TimeEvent = {
    id: string;
    eventtype: string;
    eventtime: Date;
    payload?: Record<string, any> | null;
};

// Liste aller faktischen Event-Typen, die die Zustandsmaschine beeinflussen
const FACTUAL_EVENT_TYPES = new Set([
    "work_start",
    "pause_start",
    "pause_end",
    "work_end",
    "auto_stop", // Wird als work_end behandelt
    "vacation_start",
    "vacation_end",
    "sick_start",
    "sick_end",
    "overtime_compensation_start",
    "overtime_compensation_end",
]);

export function deriveTimeSpans(allValidEvents: TimeEvent[]): DerivedSpan[] {

    // 1. FILTERN: Nur faktische Events verarbeiten
    const events = allValidEvents.filter(event =>
        FACTUAL_EVENT_TYPES.has(event.eventtype)
    );

    const spans: DerivedSpan[] = [];

    let state: State = "IDLE";
    let currentStart: Date | null = null;
    let currentType: DerivedSpan["type"] | null = null;
    let sourceEventIds: string[] = [];
    let currentPayload: Record<string, any> | null = null;

    const closeSpan = (end: Date) => {
        if (!currentStart || !currentType) return;
        if (end.getTime() <= currentStart.getTime()) {
            currentStart = null;
            currentType = null;
            sourceEventIds = [];
            currentPayload = null;
            return;
        }

        spans.push({
            type: currentType,
            startedAt: currentStart,
            endedAt: end,
            sourceEventIds: [...sourceEventIds],
            // Standardstatus ist "factual", wird später angereichert
            status: "factual",
            payload: currentPayload,
            description: currentPayload?.description || ""
        });

        currentStart = null;
        currentType = null;
        sourceEventIds = [];
        currentPayload = null;
    };

    const closeOpenSpanAsRunning = () => {
        if (!currentStart || !currentType) return;

        spans.push({
            type: currentType,
            startedAt: currentStart,
            endedAt: null,
            sourceEventIds: [...sourceEventIds],
            // Standardstatus ist "factual", wird später angereichert
            status: "factual",
            payload: currentPayload,
            description: currentPayload?.description || ""
        });

        currentStart = null;
        currentType = null;
        sourceEventIds = [];
        currentPayload = null;
    };

    for (const event of events) {
        sourceEventIds.push(event.id);

        switch (event.eventtype) {
            /* =========================
               ARBEITSZEIT
            ========================= */

            case "work_start":
                if (state === "WORKING" || state === "PAUSED" || state === "ABSENT") {
                    // Schließt die vorherige Spanne (falls z.B. work_start nach sick_start kommt)
                    closeSpan(event.eventtime);
                }
                state = "WORKING";
                currentStart = event.eventtime;
                currentType = "work";
                currentPayload = event.payload || null;
                break;

            case "pause_start":
                if (state === "WORKING") {
                    closeSpan(event.eventtime);
                    state = "PAUSED";
                    currentStart = event.eventtime;
                    currentType = "pause";
                    currentPayload = event.payload || null;
                }
                break;

            case "pause_end":
                if (state === "PAUSED") {
                    closeSpan(event.eventtime);
                    state = "WORKING";
                    currentStart = event.eventtime;
                    currentType = "work";
                    currentPayload = event.payload || null;
                }
                break;

            case "work_end":
            case "auto_stop":
                if (state === "WORKING" || state === "PAUSED") {
                    closeSpan(event.eventtime);
                }
                state = "IDLE";
                break;

            /* =========================
               ABWESENHEITEN
            ========================= */

            case "vacation_start":
            case "sick_start":
            case "overtime_compensation_start":
                // Mappt den Event-Typ direkt auf den Span-Typ
                const newType = event.eventtype.split('_')[0] as DerivedSpan["type"];

                if (state !== "IDLE") {
                    closeSpan(event.eventtime);
                }
                state = "ABSENT";
                currentStart = event.eventtime;
                currentType = newType;
                currentPayload = event.payload || null;
                break;

            case "vacation_end":
            case "sick_end":
            case "overtime_compensation_end":
                // Extrahiert den Typ der zu beendenden Spanne
                const endedType = event.eventtype.split('_')[0] as DerivedSpan["type"];

                if (state === "ABSENT" && currentType === endedType) {
                    closeSpan(event.eventtime);
                }
                state = "IDLE";
                break;
        }
    }

    // 🔴 WICHTIG: Offene Spannen als laufend zurückgeben
    if (state !== "IDLE") {
        closeOpenSpanAsRunning();
    }

    return spans;
}
