// src/services/loadValidEvents.ts

import { stafftimeevents } from "../../../db/schema";
import {sql, and, eq, gte, lte, inArray} from "drizzle-orm";
import { FastifyInstance } from "fastify";

export type TimeType = "work_start" | "work_end" | "pause_start" | "pause_end" | "sick_start" | "sick_end" | "vacation_start" | "vacation_end" | "ovetime_compensation_start" | "overtime_compensation_end";


// Die Definition des TimeEvent Typs, der zurückgegeben wird (muss mit dem tatsächlichen Typ übereinstimmen)
export type TimeEvent = {
    id: string;
    eventtype: string;
    eventtime: Date;
    actoruser_id: string;
    related_event_id: string | null;
    // Fügen Sie hier alle weiteren Felder hinzu, die Sie benötigen
};

export async function loadValidEvents(
    server: FastifyInstance,
    tenantId: number,
    userId: string,
    from: Date,
    to: Date
): Promise<TimeEvent[]> {
    // Definieren Sie einen Alias für die stafftimeevents Tabelle in der äußeren Abfrage
    const baseEvents = stafftimeevents;

    // Die Subquery, um alle IDs zu finden, die ungültig gemacht wurden
    // Wir nennen die innere Tabelle 'invalidatingEvents'
    const invalidatingEvents = server.db
        .select({
            invalidatedId: baseEvents.invalidates_event_id
        })
        .from(baseEvents)
        .as('invalidating_events');

    // Die Hauptabfrage
    const result = await server.db
        .select()
        .from(baseEvents)
        .where(
            and(
                // 1. Tenant und User filtern
                eq(baseEvents.tenant_id, tenantId),
                eq(baseEvents.user_id, userId),

                // 2. Zeitbereich filtern (Typensicher)
                gte(baseEvents.eventtime, from),
                lte(baseEvents.eventtime, to),

                // 3. WICHTIG: Korrekturen ausschließen (NOT EXISTS)
                // Schließe jedes Event aus, dessen ID in der Liste der invalidates_event_id erscheint.
                sql`
                    not exists (
                        select 1
                        from ${stafftimeevents} i
                        where i.invalidates_event_id = ${baseEvents.id}
                    )
                `
            )
        )
        .orderBy(
            // Wichtig für die deriveTimeSpans Logik: Event-Zeit muss primär sein
            baseEvents.eventtime,
            baseEvents.created_at, // Wenn Eventtime identisch ist, das später erstellte zuerst
            baseEvents.id
        );

    // Mapping auf den sauberen TimeEvent Typ
    return result.map(e => ({
        id: e.id,
        eventtype: e.eventtype,
        eventtime: e.eventtime,
        // Fügen Sie hier alle weiteren benötigten Felder hinzu (z.B. metadata, actoruser_id)
        // ...
    })) as TimeEvent[];
}

export async function loadRelatedAdminEvents(server, eventIds) {
    if (eventIds.length === 0) return [];

    // Lädt alle administrativen Events, die sich auf die faktischen Event-IDs beziehen
    const adminEvents = await server.db
        .select()
        .from(stafftimeevents)
        .where(
            and(
                inArray(stafftimeevents.related_event_id, eventIds),
                // Wir müssen hier die Entkräftung prüfen, um z.B. einen abgelehnten submitted-Event auszuschließen
                sql`
                    not exists (
                      select 1
                      from ${stafftimeevents} i
                      where i.invalidates_event_id = ${stafftimeevents}.id
                    )
                `,
            )
        )
        // Muss nach Zeit sortiert sein, um den Status korrekt zu bestimmen!
        .orderBy(stafftimeevents.eventtime);

    return adminEvents;
}