/**
 * Shared calendar sync utility for booking routes.
 *
 * Syncs a new booking to the user's connected calendar (Google or Outlook).
 * This is a non-blocking operation — failures are logged but don't affect the booking.
 */

import { prisma } from "@/lib/db";
import { bookingNotesAdapter } from "@/lib/adapters/bookings";
import { logger } from "@/lib/logger";
import { getErrorMessage } from "@/lib/errors";
import {
  hasGoogleCalendarConnection,
  listUserCalendars as listGoogleCalendars,
  createCalendarEvent as createGoogleCalendarEvent,
  type CreateEventInput as GoogleEventInput,
} from "@/lib/services/google-calendar-user.service";
import {
  hasOutlookConnection,
  listUserCalendars as listOutlookCalendars,
  createCalendarEvent as createOutlookCalendarEvent,
  type CreateOutlookEventInput,
} from "@/lib/services/outlook-calendar.service";

/** Default timezone for GCC region */
const DEFAULT_CALENDAR_TIMEZONE = "Asia/Qatar";

export interface CalendarSyncBooking {
  id: string;
  customerName: string;
  customerPhone: string;
  customerEmail?: string | null;
  service: string;
  appointmentDate: Date;
  appointmentTime: string;
  duration: number;
  notes?: string | null;
  staffMember?: string | null;
}

export async function syncBookingToCalendar(
  userId: string,
  booking: CalendarSyncBooking,
) {
  try {
    // Get user's timezone from preferences, fallback to GCC default
    const preferences = await prisma.user_preferences.findUnique({
      where: { userId },
      select: { timezone: true },
    });
    const timeZone = preferences?.timezone || DEFAULT_CALENDAR_TIMEZONE;

    // Calculate start and end datetime
    const [hours, minutes] = booking.appointmentTime.split(":").map(Number);
    const startDateTime = new Date(booking.appointmentDate);
    startDateTime.setHours(hours, minutes, 0, 0);

    const endDateTime = new Date(startDateTime);
    endDateTime.setMinutes(endDateTime.getMinutes() + booking.duration);

    // Build event description
    const description = [
      `Customer: ${booking.customerName}`,
      `Phone: ${booking.customerPhone}`,
      booking.customerEmail ? `Email: ${booking.customerEmail}` : "",
      booking.staffMember ? `Staff: ${booking.staffMember}` : "",
      booking.notes ? `Notes: ${booking.notes}` : "",
      "",
      "Created via Mawidi",
    ]
      .filter(Boolean)
      .join("\n");

    // Check for Google Calendar connection first
    const { connected: googleConnected } =
      await hasGoogleCalendarConnection(userId);
    if (googleConnected) {
      const calendars = await listGoogleCalendars(userId);
      if (calendars && calendars.length > 0) {
        const primaryCalendar =
          calendars.find((c) => c.primary) || calendars[0];

        const googleEvent: GoogleEventInput = {
          summary: `${booking.service} - ${booking.customerName}`,
          description,
          start: {
            dateTime: startDateTime.toISOString(),
            timeZone,
          },
          end: {
            dateTime: endDateTime.toISOString(),
            timeZone,
          },
          attendees: booking.customerEmail
            ? [
                {
                  email: booking.customerEmail,
                  displayName: booking.customerName,
                },
              ]
            : undefined,
        };

        const createdEvent = await createGoogleCalendarEvent(
          userId,
          primaryCalendar.id,
          googleEvent,
        );
        if (createdEvent) {
          logger.info("Booking synced to Google Calendar", {
            bookingId: booking.id,
            eventId: createdEvent.id,
            calendarId: primaryCalendar.id,
          });

          // Store the Google event ID in booking notes for future sync
          try {
            const noteNow = new Date();
            await bookingNotesAdapter.create({
              data: {
                id: `gcal-${booking.id}-${Date.now()}`,
                bookingId: booking.id,
                content: `google_calendar_event_id:${createdEvent.id}`,
                authorId: userId,
                authorName: "System",
                createdAt: noteNow,
                updatedAt: noteNow,
              },
            });
          } catch (noteError) {
            logger.warn("Failed to store Google event ID in booking notes", {
              bookingId: booking.id,
              error:
                noteError instanceof Error
                  ? noteError.message
                  : "Unknown error",
            });
          }
        }
        return; // Google Calendar sync done, no need for Outlook
      }
    }

    // Check for Outlook Calendar connection if Google not connected
    const { connected: outlookConnected } = await hasOutlookConnection(userId);
    if (outlookConnected) {
      const calendars = await listOutlookCalendars(userId);
      if (calendars && calendars.length > 0) {
        const defaultCalendar =
          calendars.find((c) => c.isDefaultCalendar) || calendars[0];

        const outlookEvent: CreateOutlookEventInput = {
          subject: `${booking.service} - ${booking.customerName}`,
          body: {
            contentType: "Text",
            content: description,
          },
          start: {
            dateTime: startDateTime.toISOString(),
            timeZone,
          },
          end: {
            dateTime: endDateTime.toISOString(),
            timeZone,
          },
          attendees: booking.customerEmail
            ? [
                {
                  emailAddress: {
                    address: booking.customerEmail,
                    name: booking.customerName,
                  },
                  type: "optional",
                },
              ]
            : undefined,
          showAs: "busy",
          isReminderOn: true,
          reminderMinutesBeforeStart: 30,
        };

        const createdEvent = await createOutlookCalendarEvent(
          userId,
          defaultCalendar.id,
          outlookEvent,
        );
        if (createdEvent) {
          logger.info("Booking synced to Outlook Calendar", {
            bookingId: booking.id,
            eventId: createdEvent.id,
            calendarId: defaultCalendar.id,
          });

          // Store the Outlook event ID in booking notes for future sync
          try {
            const outlookNoteNow = new Date();
            await bookingNotesAdapter.create({
              data: {
                id: `outlook-${booking.id}-${Date.now()}`,
                bookingId: booking.id,
                content: `outlook_calendar_event_id:${createdEvent.id}`,
                authorId: userId,
                authorName: "System",
                createdAt: outlookNoteNow,
                updatedAt: outlookNoteNow,
              },
            });
          } catch (noteError) {
            logger.warn("Failed to store Outlook event ID in booking notes", {
              bookingId: booking.id,
              error:
                noteError instanceof Error
                  ? noteError.message
                  : "Unknown error",
            });
          }
        }
      }
    }

    // No calendar integration connected - this is fine, just log it
    logger.debug("No calendar integration connected for user", { userId });
  } catch (error) {
    // Log but don't fail - calendar sync is non-critical
    logger.error("Calendar sync failed (non-blocking)", {
      bookingId: booking.id,
      userId,
      error: getErrorMessage(error),
    });
  }
}
