/**
 * Google Calendar Integration
 *
 * Provides functionality to create Google Calendar events with Google Meet links
 * for demo bookings. Uses service account authentication for server-to-server API calls.
 *
 * Environment Variables Required:
 * - GOOGLE_SERVICE_ACCOUNT_EMAIL: Service account email
 * - GOOGLE_SERVICE_ACCOUNT_KEY: Service account private key (base64 encoded)
 * - GOOGLE_CALENDAR_ID: Calendar ID to create events in
 * - GOOGLE_CALENDAR_IMPERSONATED_USER: (Optional) User to impersonate for domain-wide delegation
 * - ENABLE_GOOGLE_CALENDAR_INTEGRATION: Feature flag (default: false)
 */

import { google, calendar_v3 } from 'googleapis';
import { JWT } from 'google-auth-library';

// Default timezone for GCC region
const DEFAULT_TIMEZONE = 'Asia/Qatar';

// IANA timezone whitelist for validation
const VALID_TIMEZONES = [
  'Asia/Qatar',
  'Asia/Dubai',
  'Asia/Riyadh',
  'Asia/Kuwait',
  'Asia/Bahrain',
  'Asia/Muscat',
  'Europe/London',
  'America/New_York',
  'UTC'
];

/**
 * Demo booking data for calendar event creation
 */
export interface DemoBookingData {
  id: string;
  fullName: string;
  email: string;
  telephone: string;
  appointmentDate: Date | string;
  appointmentTime: string; // Format: "HH:MM" (e.g., "14:30")
  duration: string; // Format: "15min", "30min", "45min", "60min"
  language: 'ar' | 'en';
  timezone?: string; // IANA timezone string
  specialRequirements?: string;
}

/**
 * Result from creating a Google Calendar event
 */
export interface CalendarEventResult {
  success: boolean;
  eventId?: string;
  conferenceId?: string;
  hangoutLink?: string;
  startTime?: string; // RFC3339 timestamp
  endTime?: string; // RFC3339 timestamp
  error?: string;
  htmlLink?: string; // Link to view event in Google Calendar
}

/**
 * Parse duration string to minutes
 */
function parseDurationToMinutes(duration: string): number {
  const match = duration.match(/^(\d+)min$/);
  if (!match) {
    throw new Error(`Invalid duration format: ${duration}. Expected format: "15min", "30min", etc.`);
  }
  return parseInt(match[1], 10);
}

/**
 * Validate timezone string against whitelist
 */
export function validateTimezone(timezone: string): boolean {
  return VALID_TIMEZONES.includes(timezone);
}

/**
 * Convert appointment date, time, and timezone to RFC3339 timestamps
 */
function convertToRFC3339(
  appointmentDate: Date | string,
  appointmentTime: string,
  timezone: string,
  durationMinutes: number
): { start: string; end: string } {
  // Parse appointment date
  const date = typeof appointmentDate === 'string'
    ? new Date(appointmentDate)
    : appointmentDate;

  // Parse time (format: "HH:MM")
  const [hours, minutes] = appointmentTime.split(':').map(Number);

  if (isNaN(hours) || isNaN(minutes) || hours < 0 || hours > 23 || minutes < 0 || minutes > 59) {
    throw new Error(`Invalid time format: ${appointmentTime}. Expected format: "HH:MM"`);
  }

  // Create start datetime in the specified timezone
  // Note: We construct the ISO string manually to avoid timezone conversion issues
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const day = String(date.getDate()).padStart(2, '0');
  const hour = String(hours).padStart(2, '0');
  const minute = String(minutes).padStart(2, '0');

  // Format: YYYY-MM-DDTHH:MM:SS (we'll add timezone offset)
  const dateTimeStr = `${year}-${month}-${day}T${hour}:${minute}:00`;

  // Calculate end time
  const endDate = new Date(date);
  endDate.setHours(hours, minutes + durationMinutes, 0, 0);
  const endHour = String(endDate.getHours()).padStart(2, '0');
  const endMinute = String(endDate.getMinutes()).padStart(2, '0');
  const endDateTimeStr = `${year}-${month}-${day}T${endHour}:${endMinute}:00`;

  return {
    start: dateTimeStr,
    end: endDateTimeStr
  };
}

/**
 * Initialize Google Calendar API client with service account authentication
 */
function getCalendarClient(): calendar_v3.Calendar | null {
  // Check if integration is enabled
  if (process.env.ENABLE_GOOGLE_CALENDAR_INTEGRATION !== 'true') {
    console.log('[Google Calendar] Integration disabled via feature flag');
    return null;
  }

  const serviceAccountEmail = process.env.GOOGLE_SERVICE_ACCOUNT_EMAIL;
  const serviceAccountKeyBase64 = process.env.GOOGLE_SERVICE_ACCOUNT_KEY;

  if (!serviceAccountEmail || !serviceAccountKeyBase64) {
    console.warn('[Google Calendar] Missing credentials: GOOGLE_SERVICE_ACCOUNT_EMAIL or GOOGLE_SERVICE_ACCOUNT_KEY');
    return null;
  }

  try {
    // Decode base64 private key
    const serviceAccountKey = Buffer.from(serviceAccountKeyBase64, 'base64').toString('utf-8');
    const keyJson = JSON.parse(serviceAccountKey);

    // Create JWT client
    const jwtClient = new JWT({
      email: keyJson.client_email || serviceAccountEmail,
      key: keyJson.private_key,
      scopes: ['https://www.googleapis.com/auth/calendar'],
      subject: process.env.GOOGLE_CALENDAR_IMPERSONATED_USER || undefined
    });

    // Return Calendar API client
    return google.calendar({ version: 'v3', auth: jwtClient });
  } catch (error) {
    console.error('[Google Calendar] Failed to initialize client:', error);
    return null;
  }
}

/**
 * Create a Google Calendar event with Google Meet link for a demo booking
 *
 * @param booking - Demo booking data
 * @returns Calendar event result with Meet link and event metadata
 */
export async function createDemoBookingEvent(
  booking: DemoBookingData
): Promise<CalendarEventResult> {
  try {
    // Initialize calendar client
    const calendar = getCalendarClient();
    if (!calendar) {
      return {
        success: false,
        error: 'Google Calendar integration not available (disabled or missing credentials)'
      };
    }

    // Validate calendar ID
    const calendarId = process.env.GOOGLE_CALENDAR_ID;
    if (!calendarId) {
      return {
        success: false,
        error: 'GOOGLE_CALENDAR_ID environment variable not set'
      };
    }

    // Validate and set timezone
    const timezone = booking.timezone || DEFAULT_TIMEZONE;
    if (!validateTimezone(timezone)) {
      console.warn(`[Google Calendar] Invalid timezone: ${timezone}, using default: ${DEFAULT_TIMEZONE}`);
    }

    // Parse duration
    const durationMinutes = parseDurationToMinutes(booking.duration);

    // Convert to RFC3339 timestamps
    const { start, end } = convertToRFC3339(
      booking.appointmentDate,
      booking.appointmentTime,
      timezone,
      durationMinutes
    );

    // Prepare event summary and description
    const summary = booking.language === 'ar'
      ? `عرض توضيحي مع ${booking.fullName}`
      : `Demo with ${booking.fullName}`;

    const descriptionParts = [
      booking.language === 'ar' ? 'عرض توضيحي لمنصة Mawidi' : 'Mawidi Platform Demo',
      '',
      booking.language === 'ar' ? `العميل: ${booking.fullName}` : `Client: ${booking.fullName}`,
      booking.language === 'ar' ? `البريد الإلكتروني: ${booking.email}` : `Email: ${booking.email}`,
      booking.language === 'ar' ? `الهاتف: ${booking.telephone}` : `Phone: ${booking.telephone}`,
      booking.language === 'ar' ? `المدة: ${booking.duration}` : `Duration: ${booking.duration}`,
    ];

    if (booking.specialRequirements) {
      descriptionParts.push(
        '',
        booking.language === 'ar' ? 'متطلبات خاصة:' : 'Special Requirements:',
        booking.specialRequirements
      );
    }

    const description = descriptionParts.join('\n');

    // Create event with Google Meet conference
    const event: calendar_v3.Schema$Event = {
      summary,
      description,
      start: {
        dateTime: start,
        timeZone: timezone
      },
      end: {
        dateTime: end,
        timeZone: timezone
      },
      attendees: [
        {
          email: booking.email,
          displayName: booking.fullName,
          responseStatus: 'needsAction'
        }
      ],
      conferenceData: {
        createRequest: {
          requestId: `mawidi-demo-${booking.id}`, // Idempotency key
          conferenceSolutionKey: {
            type: 'hangoutsMeet'
          }
        }
      },
      reminders: {
        useDefault: false,
        overrides: [
          { method: 'email', minutes: 24 * 60 }, // 1 day before
          { method: 'popup', minutes: 30 } // 30 minutes before
        ]
      },
      guestsCanModify: false,
      guestsCanInviteOthers: false,
      guestsCanSeeOtherGuests: false
    };

    // Create event with retry logic
    let retries = 3;
    let lastError: any;

    while (retries > 0) {
      try {
        const response = await calendar.events.insert({
          calendarId,
          conferenceDataVersion: 1,
          sendUpdates: 'all', // Send email invitations to attendees
          requestBody: event
        });

        const createdEvent = response.data;

        // Extract Meet link and metadata
        const hangoutLink = createdEvent.hangoutLink || createdEvent.conferenceData?.entryPoints?.find(
          (ep) => ep.entryPointType === 'video'
        )?.uri;

        const conferenceId = createdEvent.conferenceData?.conferenceId;

        console.log(`[Google Calendar] Successfully created event ${createdEvent.id} with Meet link`);

        return {
          success: true,
          eventId: createdEvent.id!,
          conferenceId,
          hangoutLink,
          startTime: start,
          endTime: end,
          htmlLink: createdEvent.htmlLink || undefined
        };
      } catch (error: any) {
        lastError = error;
        retries--;

        if (retries > 0 && error?.code >= 500) {
          // Retry on server errors
          console.warn(`[Google Calendar] Transient error, retrying... (${retries} attempts left)`, error.message);
          await new Promise(resolve => setTimeout(resolve, 1000 * (4 - retries))); // Exponential backoff
        } else {
          break;
        }
      }
    }

    // All retries failed
    console.error('[Google Calendar] Failed to create event after retries:', lastError);
    return {
      success: false,
      error: lastError?.message || 'Unknown error creating calendar event'
    };

  } catch (error: any) {
    console.error('[Google Calendar] Unexpected error:', error);
    return {
      success: false,
      error: error?.message || 'Unexpected error creating calendar event'
    };
  }
}

/**
 * Update an existing Google Calendar event
 * Useful for rescheduling or modifying event details
 */
export async function updateDemoBookingEvent(
  eventId: string,
  booking: Partial<DemoBookingData>
): Promise<CalendarEventResult> {
  try {
    const calendar = getCalendarClient();
    if (!calendar) {
      return {
        success: false,
        error: 'Google Calendar integration not available'
      };
    }

    const calendarId = process.env.GOOGLE_CALENDAR_ID;
    if (!calendarId) {
      return {
        success: false,
        error: 'GOOGLE_CALENDAR_ID not set'
      };
    }

    // Get existing event
    const existingEvent = await calendar.events.get({
      calendarId,
      eventId
    });

    // Update only provided fields
    const updatedEvent: calendar_v3.Schema$Event = {
      ...existingEvent.data
    };

    // Update time if provided
    if (booking.appointmentDate && booking.appointmentTime && booking.duration) {
      const timezone = booking.timezone || DEFAULT_TIMEZONE;
      const durationMinutes = parseDurationToMinutes(booking.duration);
      const { start, end } = convertToRFC3339(
        booking.appointmentDate,
        booking.appointmentTime,
        timezone,
        durationMinutes
      );
      updatedEvent.start = { dateTime: start, timeZone: timezone };
      updatedEvent.end = { dateTime: end, timeZone: timezone };
    }

    // Update event
    const response = await calendar.events.update({
      calendarId,
      eventId,
      conferenceDataVersion: 1,
      sendUpdates: 'all',
      requestBody: updatedEvent
    });

    return {
      success: true,
      eventId: response.data.id!,
      hangoutLink: response.data.hangoutLink || undefined,
      htmlLink: response.data.htmlLink || undefined
    };

  } catch (error: any) {
    console.error('[Google Calendar] Failed to update event:', error);
    return {
      success: false,
      error: error?.message || 'Failed to update calendar event'
    };
  }
}

/**
 * Cancel a Google Calendar event
 */
export async function cancelDemoBookingEvent(
  eventId: string,
  sendUpdates: boolean = true
): Promise<{ success: boolean; error?: string }> {
  try {
    const calendar = getCalendarClient();
    if (!calendar) {
      return {
        success: false,
        error: 'Google Calendar integration not available'
      };
    }

    const calendarId = process.env.GOOGLE_CALENDAR_ID;
    if (!calendarId) {
      return {
        success: false,
        error: 'GOOGLE_CALENDAR_ID not set'
      };
    }

    await calendar.events.delete({
      calendarId,
      eventId,
      sendUpdates: sendUpdates ? 'all' : 'none'
    });

    console.log(`[Google Calendar] Successfully cancelled event ${eventId}`);
    return { success: true };

  } catch (error: any) {
    console.error('[Google Calendar] Failed to cancel event:', error);
    return {
      success: false,
      error: error?.message || 'Failed to cancel calendar event'
    };
  }
}
