// @ts-nocheck
/* eslint-disable @typescript-eslint/no-explicit-any */

import { prisma } from './prisma';
import { getCalendarEvents, CalendarEvent, CalendarConnection } from './calendar-events';

const STALE_THRESHOLD_MS = 2 * 60 * 1000; // 2 minutes — match background sync interval

/**
 * Get the Monday (start of ISO week) for a given date.
 */
function getWeekStart(date: Date): Date {
    const d = new Date(date);
    d.setUTCHours(0, 0, 0, 0);
    const day = d.getUTCDay(); // 0=Sun
    const diff = day === 0 ? -6 : 1 - day;
    d.setUTCDate(d.getUTCDate() + diff);
    return d;
}

/**
 * Check if the cache for a given connection + time window is stale.
 */
export async function isCacheStale(
    connectionId: string,
    timeMin: Date,
): Promise<boolean> {
    const weekStart = getWeekStart(timeMin);
    const newest = await prisma.cachedCalendarEvent.findFirst({
        where: { connectionId, weekStart },
        orderBy: { syncedAt: 'desc' },
        select: { syncedAt: true },
    });
    if (!newest) return true;
    return Date.now() - newest.syncedAt.getTime() > STALE_THRESHOLD_MS;
}

/**
 * Read cached events for a user within a date range.
 * Returns them in the flat shape the frontend expects.
 */
export async function readCachedEvents(
    userId: string,
    timeMin: Date,
    timeMax: Date,
) {
    const minDateStr = timeMin.toISOString().slice(0, 10);
    const maxDateStr = timeMax.toISOString().slice(0, 10);

    const rows = await prisma.cachedCalendarEvent.findMany({
        where: {
            userId,
            OR: [
                // Timed events within range
                {
                    startDateTime: { gte: timeMin, lte: timeMax },
                },
                // All-day events within range
                {
                    startDate: { gte: minDateStr, lte: maxDateStr },
                },
            ],
        },
        orderBy: { startDateTime: 'asc' },
    });

    return rows.map(row => ({
        id: row.externalId,
        title: row.title,
        description: row.description,
        location: row.location,
        url: row.url,
        recurringEventId: row.recurringEventId,
        isRecurring: row.isRecurring,
        startTime: row.startDateTime?.toISOString() ?? row.startDate ?? '',
        endTime: row.endDateTime?.toISOString() ?? row.endDate ?? '',
        source: row.provider as 'google' | 'apple' | 'outlook' | 'synology',
        calendarId: row.calendarId,
        calendarTitle: row.calendarTitle,
        calendarColor: row.calendarColor,
    }));
}

export interface RefreshableConnection extends CalendarConnection {
    dbId: string;
    userId: string;
}

/**
 * Fetch live events from provider, then atomic swap into cache.
 */
export async function refreshConnectionCache(
    connection: RefreshableConnection,
    timeMin: Date,
    timeMax: Date,
): Promise<number> {
    const weekStart = getWeekStart(timeMin);

    let liveEvents: CalendarEvent[] = [];
    try {
        liveEvents = await getCalendarEvents(
            [connection],
            timeMin.toISOString(),
            timeMax.toISOString(),
        );
    } catch (err) {
        console.error(`[CACHE] Live fetch failed for connection ${connection.dbId}:`, err);
        return 0;
    }

    const now = new Date();
    const rows = liveEvents.map(ev => ({
        userId: connection.userId,
        externalId: ev.id,
        connectionId: connection.dbId,
        provider: connection.provider,
        calendarId: ev.calendarId,
        calendarTitle: ev.calendarTitle,
        calendarColor: ev.backgroundColor ?? null,
        title: ev.title,
        description: ev.description ?? null,
        location: ev.location ?? null,
        url: ev.url ?? null,
        recurringEventId: ev.recurringEventId ?? null,
        isRecurring: ev.isRecurring ?? false,
        startDateTime: ev.start.dateTime ? new Date(ev.start.dateTime) : null,
        startDate: ev.start.date ?? null,
        endDateTime: ev.end.dateTime ? new Date(ev.end.dateTime) : null,
        endDate: ev.end.date ?? null,
        reminders: ev.reminders ? JSON.parse(JSON.stringify(ev.reminders)) : null,
        weekStart,
        syncedAt: now,
    }));

    // Atomic swap: delete old events for this connection+week, insert fresh ones
    await prisma.$transaction([
        prisma.cachedCalendarEvent.deleteMany({
            where: { connectionId: connection.dbId, weekStart },
        }),
        prisma.cachedCalendarEvent.createMany({
            data: rows,
            skipDuplicates: true,
        }),
    ]);

    console.log(`[CACHE] Refreshed ${rows.length} events for ${connection.provider} connection, week ${weekStart.toISOString().slice(0, 10)}`);
    return rows.length;
}

/**
 * Upsert a single event into cache (after create/update mutations).
 */
export async function upsertCachedEvent(
    userId: string,
    connectionId: string,
    provider: string,
    event: CalendarEvent,
): Promise<void> {
    const weekStart = getWeekStart(
        new Date(event.start.dateTime ?? event.start.date ?? Date.now()),
    );

    await prisma.cachedCalendarEvent.upsert({
        where: {
            userId_externalId_provider: { userId, externalId: event.id, provider },
        },
        create: {
            userId,
            externalId: event.id,
            connectionId,
            provider,
            calendarId: event.calendarId,
            calendarTitle: event.calendarTitle,
            calendarColor: event.backgroundColor ?? null,
            title: event.title,
            description: event.description ?? null,
            location: event.location ?? null,
            url: event.url ?? null,
            recurringEventId: event.recurringEventId ?? null,
            isRecurring: event.isRecurring ?? false,
            startDateTime: event.start.dateTime ? new Date(event.start.dateTime) : null,
            startDate: event.start.date ?? null,
            endDateTime: event.end.dateTime ? new Date(event.end.dateTime) : null,
            endDate: event.end.date ?? null,
            reminders: event.reminders ? JSON.parse(JSON.stringify(event.reminders)) : null,
            weekStart,
            syncedAt: new Date(),
        },
        update: {
            calendarTitle: event.calendarTitle,
            calendarColor: event.backgroundColor ?? null,
            title: event.title,
            description: event.description ?? null,
            location: event.location ?? null,
            url: event.url ?? null,
            recurringEventId: event.recurringEventId ?? null,
            isRecurring: event.isRecurring ?? false,
            startDateTime: event.start.dateTime ? new Date(event.start.dateTime) : null,
            startDate: event.start.date ?? null,
            endDateTime: event.end.dateTime ? new Date(event.end.dateTime) : null,
            endDate: event.end.date ?? null,
            reminders: event.reminders ? JSON.parse(JSON.stringify(event.reminders)) : null,
            weekStart,
            syncedAt: new Date(),
        },
    });
}

/**
 * Delete a single cached event (after delete mutations).
 */
export async function deleteCachedEvent(
    userId: string,
    externalId: string,
    provider: string,
): Promise<void> {
    await prisma.cachedCalendarEvent.deleteMany({
        where: { userId, externalId, provider },
    });
}
