import { FastifyInstance } from "fastify";
import {and, eq, gte, lte, asc, inArray} from "drizzle-orm";
import {
    authProfiles,
    stafftimeentries,
    holidays,
} from "../../../db/schema";

export async function generateTimesEvaluation(
    server: FastifyInstance,
    user_id: string,
    tenant_id: number,
    startDateInput: string,
    endDateInput: string
) {
    const startDate = server.dayjs(startDateInput);
    const endDate = server.dayjs(endDateInput);

    console.log(startDate.format("YYYY-MM-DD HH:mm:ss"));
    console.log(endDate.format("YYYY-MM-DD HH:mm:ss"));

    // -------------------------------------------------------------
    // 1️⃣ Profil laden
    // -------------------------------------------------------------
    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.");

    // -------------------------------------------------------------
    // 2️⃣ Arbeitszeiten laden
    // -------------------------------------------------------------
    const timesRaw = await server.db
        .select()
        .from(stafftimeentries)
        .where(
            and(
                eq(stafftimeentries.tenant_id, tenant_id),
                eq(stafftimeentries.user_id, user_id)
            )
        )
        .orderBy(asc(stafftimeentries.started_at));

    const isBetween = (spanStartDate, spanEndDate, startDate, endDate) => {
        return (
            server
                .dayjs(startDate)
                .isBetween(spanStartDate, spanEndDate, "day", "[]") &&
            server
                .dayjs(endDate)
                .isBetween(spanStartDate, spanEndDate, "day", "[]")
        );
    };

    const times = timesRaw.filter((i) =>
        isBetween(startDate, endDate, i.started_at, i.stopped_at)
    );

    console.log(times);

    // -------------------------------------------------------------
    // 3️⃣ Feiertage laden
    // -------------------------------------------------------------
    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"))
            )
        );

    // -------------------------------------------------------------
    // 4️⃣ Sollzeit berechnen
    // -------------------------------------------------------------
    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;
    }

    // -------------------------------------------------------------
    // 5️⃣ Eingereicht/genehmigt
    // -------------------------------------------------------------
    const calcMinutes = (start: string, end: string | null) =>
        server.dayjs(end || new Date()).diff(server.dayjs(start), "minutes");

    let sumWorkingMinutesEingereicht = 0;
    let sumWorkingMinutesApproved = 0;

    for (const t of times) {
        // @ts-ignore
        const minutes = calcMinutes(t.started_at, t.stopped_at);

        if (["submitted", "approved"].includes(t.state) && t.type === "work") {
            sumWorkingMinutesEingereicht += minutes;
        }
        if (t.state === "approved" && t.type === "work") {
            sumWorkingMinutesApproved += minutes;
        }
    }

    // -------------------------------------------------------------
    // 6️⃣ Feiertagsausgleich
    // -------------------------------------------------------------
    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++;
        });
    }

    // -------------------------------------------------------------
    // 7️⃣ Urlaub
    // -------------------------------------------------------------
    let sumWorkingMinutesVacationDays = 0;
    let sumVacationDays = 0;

    times
        .filter((t) => t.type === "vacation" && t.state === "approved")
        .forEach((time) => {
            // Tippfehler aus Original: startet_at vs started_at → NICHT korrigiert
            const days =
                server.dayjs(time.stopped_at).diff(
                    //@ts-ignore
                    server.dayjs(time.startet_at),
                    "day"
                ) + 1;

            for (let i = 0; i < days; i++) {
                const weekday = server
                    .dayjs(time.started_at)
                    .add(i, "day")
                    .day();
                const hours =
                    profile.weekly_regular_working_hours?.[weekday] || 0;
                sumWorkingMinutesVacationDays += hours * 60;
            }
            sumVacationDays += days;
        });

    // -------------------------------------------------------------
    // 8️⃣ Krankheit
    // -------------------------------------------------------------
    let sumWorkingMinutesSickDays = 0;
    let sumSickDays = 0;

    times
        .filter((t) => t.type === "sick" && t.state === "approved")
        .forEach((time) => {
            const days =
                server.dayjs(time.stopped_at).diff(
                    //@ts-ignore
                    server.dayjs(time.startet_at),
                    "day"
                ) + 1;

            for (let i = 0; i < days; i++) {
                const weekday = server
                    .dayjs(time.started_at)
                    .add(i, "day")
                    .day();
                const hours =
                    profile.weekly_regular_working_hours?.[weekday] || 0;
                sumWorkingMinutesSickDays += hours * 60;
            }

            sumSickDays += days;
        });

    // -------------------------------------------------------------
    // 9️⃣ Salden
    // -------------------------------------------------------------
    const saldo =
        sumWorkingMinutesApproved +
        sumWorkingMinutesRecreationDays +
        sumWorkingMinutesVacationDays +
        sumWorkingMinutesSickDays -
        timeSpanWorkingMinutes;

    const saldoInOfficial =
        sumWorkingMinutesEingereicht +
        sumWorkingMinutesRecreationDays +
        sumWorkingMinutesVacationDays +
        sumWorkingMinutesSickDays -
        timeSpanWorkingMinutes;

    // -------------------------------------------------------------
    // 🔟 Rückgabe identisch
    // -------------------------------------------------------------
    return {
        user_id,
        tenant_id,
        from: startDate.format("YYYY-MM-DD"),
        to: endDate.format("YYYY-MM-DD"),
        timeSpanWorkingMinutes,
        sumWorkingMinutesEingereicht,
        sumWorkingMinutesApproved,
        sumWorkingMinutesRecreationDays,
        sumRecreationDays,
        sumWorkingMinutesVacationDays,
        sumVacationDays,
        sumWorkingMinutesSickDays,
        sumSickDays,
        saldo,
        saldoInOfficial,
        times,
    };
}
