// src/services/buildTimeEvaluationFromSpans.ts

import { FastifyInstance } from "fastify";
import { and, eq, gte, lte, inArray } from "drizzle-orm";
import { authProfiles, holidays } from "../../../db/schema";
import { DerivedSpan } from "./derivetimespans.service"; // Importiert den angereicherten Span-Typ

// Definiert das erwartete Rückgabeformat
export type TimeEvaluationResult = {
    user_id: string;
    tenant_id: number;
    from: string;
    to: string;

    // Sollzeit
    timeSpanWorkingMinutes: number;

    // Arbeitszeit Salden
    sumWorkingMinutesSubmitted: number;
    sumWorkingMinutesApproved: number;

    // Abwesenheiten (minuten und Tage)
    sumWorkingMinutesRecreationDays: number;
    sumRecreationDays: number;
    sumWorkingMinutesVacationDays: number;
    sumVacationDays: number;
    sumWorkingMinutesSickDays: number;
    sumSickDays: number;

    // Endsalden
    saldoApproved: number; // Saldo basierend auf genehmigter Zeit
    saldoSubmitted: number; // Saldo basierend auf eingereichter/genehmigter Zeit

    spans: DerivedSpan[];
};

// Hilfsfunktion zur Berechnung der Minuten (nur für geschlossene Spannen)
const calcMinutes = (start: Date, end: Date | null): number => {
    if (!end) return 0;
    return (end.getTime() - start.getTime()) / 60000;
};


export async function buildTimeEvaluationFromSpans(
    server: FastifyInstance,
    user_id: string,
    tenant_id: number,
    startDateInput: string,
    endDateInput: string,
    // Der wichtigste Unterschied: Wir nehmen die angereicherten Spannen als Input
    spans: DerivedSpan[]
): Promise<TimeEvaluationResult> {

    const startDate = server.dayjs(startDateInput);
    const endDate = server.dayjs(endDateInput);

    // -------------------------------------------------------------
    // 1️⃣ Profil und Feiertage laden (WIE IM ALTEN SERVICE)
    // -------------------------------------------------------------

    const profileRows = await server.db
        .select()
        .from(authProfiles)
        .where(
            and(
                eq(authProfiles.user_id, user_id),
                eq(authProfiles.tenant_id, tenant_id)
            )
        )
        .limit(1);

    const profile = profileRows[0];
    if (!profile) throw new Error("Profil konnte nicht geladen werden.");

    const holidaysRows = await server.db
        .select({
            date: holidays.date,
        })
        .from(holidays)
        .where(
            and(
                inArray(holidays.state_code, [profile.state_code, "DE"]),
                gte(holidays.date, startDate.format("YYYY-MM-DD")),
                lte(holidays.date, endDate.add(1, "day").format("YYYY-MM-DD"))
            )
        );

    // -------------------------------------------------------------
    // 2️⃣ Sollzeit berechnen (WIE IM ALTEN SERVICE)
    // -------------------------------------------------------------
    let timeSpanWorkingMinutes = 0;
    const totalDays = endDate.add(1, "day").diff(startDate, "days");

    for (let i = 0; i < totalDays; i++) {
        const date = startDate.add(i, "days");
        const weekday = date.day();
        timeSpanWorkingMinutes +=
            (profile.weekly_regular_working_hours?.[weekday] || 0) * 60;
    }


    // -------------------------------------------------------------
    // 3️⃣ Arbeits- und Abwesenheitszeiten berechnen (NEUE LOGIK)
    // -------------------------------------------------------------

    let sumWorkingMinutesSubmitted = 0;
    let sumWorkingMinutesApproved = 0;

    let sumWorkingMinutesVacationDays = 0;
    let sumVacationDays = 0;
    let sumWorkingMinutesSickDays = 0;
    let sumSickDays = 0;

    // Akkumulieren der Zeiten basierend auf dem abgeleiteten Typ und Status
    for (const span of spans) {

        // **A. Arbeitszeiten (WORK)**
        if (span.type === "work") {
            const minutes = calcMinutes(span.startedAt, span.endedAt);

            // Zähle zur eingereichten Summe, wenn der Status submitted oder approved ist
            if (span.status === "submitted" || span.status === "approved") {
                sumWorkingMinutesSubmitted += minutes;
            }

            // Zähle zur genehmigten Summe, wenn der Status approved ist
            if (span.status === "approved") {
                sumWorkingMinutesApproved += minutes;
            }
        }

        // **B. Abwesenheiten (VACATION, SICK)**
        // Wir verwenden die Logik aus dem alten Service: Berechnung der Sollzeit
        // basierend auf den Tagen der Span (Voraussetzung: Spannen sind Volltages-Spannen)
        if (span.type === "vacation" || span.type === "sick") {

            // Behandle nur genehmigte Abwesenheiten für die Saldenberechnung
            if (span.status !== "approved") {
                continue;
            }

            const startDay = server.dayjs(span.startedAt).startOf('day');
            // Wenn endedAt null ist (offene Span), nehmen wir das Ende des Zeitraums
            const endDay = span.endedAt ? server.dayjs(span.endedAt).startOf('day') : endDate.startOf('day');

            // Berechnung der Tage der Span
            const days = endDay.diff(startDay, "day") + 1;

            for (let i = 0; i < days; i++) {
                const day = startDay.add(i, "day");
                const weekday = day.day();
                const hours = profile.weekly_regular_working_hours?.[weekday] || 0;

                if (span.type === "vacation") {
                    sumWorkingMinutesVacationDays += hours * 60;
                } else if (span.type === "sick") {
                    sumWorkingMinutesSickDays += hours * 60;
                }
            }

            if (span.type === "vacation") {
                sumVacationDays += days;
            } else if (span.type === "sick") {
                sumSickDays += days;
            }
        }

        // PAUSE Spannen werden ignoriert, da sie in der faktischen Ableitung bereits von WORK abgezogen wurden.
    }


    // -------------------------------------------------------------
    // 4️⃣ Feiertagsausgleich (WIE IM ALTEN SERVICE)
    // -------------------------------------------------------------
    let sumWorkingMinutesRecreationDays = 0;
    let sumRecreationDays = 0;

    if (profile.recreation_days_compensation && holidaysRows?.length) {
        holidaysRows.forEach(({ date }) => {
            const weekday = server.dayjs(date).day();
            const hours = profile.weekly_regular_working_hours?.[weekday] || 0;
            sumWorkingMinutesRecreationDays += hours * 60;
            sumRecreationDays++;
        });
    }

    // -------------------------------------------------------------
    // 5️⃣ Salden berechnen (NEUE LOGIK)
    // -------------------------------------------------------------

    const totalCompensatedMinutes =
        sumWorkingMinutesRecreationDays +
        sumWorkingMinutesVacationDays +
        sumWorkingMinutesSickDays;

    // Saldo basierend auf GENEHMIGTER Arbeitszeit
    const totalApprovedMinutes = sumWorkingMinutesApproved + totalCompensatedMinutes;
    const saldoApproved = totalApprovedMinutes - timeSpanWorkingMinutes;

    // Saldo basierend auf EINGEREICHTER und GENEHMIGTER Arbeitszeit
    const totalSubmittedMinutes = sumWorkingMinutesSubmitted + totalCompensatedMinutes;
    const saldoSubmitted = totalSubmittedMinutes - timeSpanWorkingMinutes;


    // -------------------------------------------------------------
    // 6️⃣ Rückgabe
    // -------------------------------------------------------------
    return {
        user_id,
        tenant_id,
        from: startDate.format("YYYY-MM-DD"),
        to: endDate.format("YYYY-MM-DD"),
        timeSpanWorkingMinutes,

        sumWorkingMinutesSubmitted,
        sumWorkingMinutesApproved,

        sumWorkingMinutesRecreationDays,
        sumRecreationDays,
        sumWorkingMinutesVacationDays,
        sumVacationDays,
        sumWorkingMinutesSickDays,
        sumSickDays,

        saldoApproved,
        saldoSubmitted,
        spans,
    };
}