import { format, formatDistanceToNow, parseISO } from 'date-fns';
import { id } from 'date-fns/locale';

/**
 * Format ISO timestamp to local timezone
 * Automatically converts to user's browser timezone
 * 
 * @param isoString - ISO 8601 timestamp from API
 * @param formatStr - date-fns format string
 * @returns Formatted date string in local timezone
 * 
 * @example
 * formatTimestamp('2026-04-28T10:44:03.000Z') // "28 Apr 2026, 17:44" (if user in WITA)
 * formatTimestamp('2026-04-28T10:44:03.000Z', 'dd/MM/yyyy') // "28/04/2026"
 */
export function formatTimestamp(
  isoString: string | null | undefined,
  formatStr: string = 'dd MMM yyyy, HH:mm'
): string {
  if (!isoString) return '-';
  
  try {
    // Parse ISO string - browser automatically converts to local timezone
    const date = parseISO(isoString);
    
    // Format with Indonesian locale
    return format(date, formatStr, { locale: id });
  } catch (error) {
    console.error('Error formatting timestamp:', error, isoString);
    return '-';
  }
}

/**
 * Format date only (without time)
 * 
 * @example
 * formatDate('2026-04-28T10:44:03.000Z') // "28 Apr 2026"
 */
export function formatDate(isoString: string | null | undefined): string {
  return formatTimestamp(isoString, 'dd MMM yyyy');
}

/**
 * Format time only (without date)
 * 
 * @example
 * formatTime('2026-04-28T10:44:03.000Z') // "17:44"
 */
export function formatTime(isoString: string | null | undefined): string {
  return formatTimestamp(isoString, 'HH:mm');
}

/**
 * Format date and time with seconds
 * 
 * @example
 * formatDateTime('2026-04-28T10:44:03.000Z') // "28 Apr 2026, 17:44:03"
 */
export function formatDateTime(isoString: string | null | undefined): string {
  return formatTimestamp(isoString, 'dd MMM yyyy, HH:mm:ss');
}

/**
 * Format relative time (e.g., "2 jam yang lalu")
 * 
 * @example
 * formatRelativeTime('2026-04-28T10:44:03.000Z') // "2 jam yang lalu"
 */
export function formatRelativeTime(isoString: string | null | undefined): string {
  if (!isoString) return '-';
  
  try {
    const date = parseISO(isoString);
    return formatDistanceToNow(date, { addSuffix: true, locale: id });
  } catch (error) {
    console.error('Error formatting relative time:', error, isoString);
    return '-';
  }
}

/**
 * Get timezone abbreviation (WIB/WITA/WIT)
 * Based on browser's detected timezone
 * 
 * @returns Timezone abbreviation
 * 
 * @example
 * getTimezoneAbbr() // "WITA" (if browser in Makassar)
 */
export function getTimezoneAbbr(): string {
  const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
  
  // Map common Indonesia timezones to abbreviations
  const tzMap: Record<string, string> = {
    // WIB (GMT+7)
    'Asia/Jakarta': 'WIB',
    'Asia/Pontianak': 'WIB',
    'Asia/Palembang': 'WIB',
    'Asia/Medan': 'WIB',
    'Asia/Bandung': 'WIB',
    
    // WITA (GMT+8)
    'Asia/Makassar': 'WITA',
    'Asia/Ujung_Pandang': 'WITA',
    'Asia/Balikpapan': 'WITA',
    'Asia/Denpasar': 'WITA',
    
    // WIT (GMT+9)
    'Asia/Jayapura': 'WIT',
  };
  
  return tzMap[tz] || 'WIB'; // default WIB
}

/**
 * Get timezone offset in hours
 * 
 * @returns Offset in hours (e.g., 7, 8, 9)
 * 
 * @example
 * getTimezoneOffset() // 8 (if in WITA)
 */
export function getTimezoneOffset(): number {
  const offset = new Date().getTimezoneOffset();
  return -offset / 60; // Convert minutes to hours and invert sign
}

/**
 * Format with timezone indicator
 * 
 * @example
 * formatWithTimezone('2026-04-28T10:44:03.000Z') // "28 Apr 2026, 17:44 WITA"
 */
export function formatWithTimezone(
  isoString: string | null | undefined,
  formatStr: string = 'dd MMM yyyy, HH:mm'
): string {
  const formatted = formatTimestamp(isoString, formatStr);
  if (formatted === '-') return '-';
  
  return `${formatted} ${getTimezoneAbbr()}`;
}

/**
 * Format for display in tables/lists
 * Shows date and time in compact format
 * 
 * @example
 * formatCompact('2026-04-28T10:44:03.000Z') // "28/04/26 17:44"
 */
export function formatCompact(isoString: string | null | undefined): string {
  return formatTimestamp(isoString, 'dd/MM/yy HH:mm');
}

/**
 * Format for long display (full month name)
 * 
 * @example
 * formatLong('2026-04-28T10:44:03.000Z') // "28 April 2026, 17:44"
 */
export function formatLong(isoString: string | null | undefined): string {
  return formatTimestamp(isoString, 'dd MMMM yyyy, HH:mm');
}

/**
 * Check if date is today
 */
export function isToday(isoString: string | null | undefined): boolean {
  if (!isoString) return false;
  
  try {
    const date = parseISO(isoString);
    const today = new Date();
    
    return date.getDate() === today.getDate() &&
           date.getMonth() === today.getMonth() &&
           date.getFullYear() === today.getFullYear();
  } catch {
    return false;
  }
}

/**
 * Format promotion period with optional time (timezone-aware)
 * Uses start_datetime/end_datetime (ISO) for proper timezone conversion.
 * Falls back to start_date/end_date if datetime not available.
 * 
 * @param startDate - Start date string (Y-m-d)
 * @param endDate - End date string (Y-m-d)
 * @param startDatetime - Optional ISO datetime string (with timezone offset)
 * @param endDatetime - Optional ISO datetime string (with timezone offset)
 * @returns Formatted period string in client timezone
 * 
 * @example
 * formatPromoPeriod('2026-06-01', '2026-06-30') // "01 Jun 2026 — 30 Jun 2026"
 * formatPromoPeriod('2026-06-01', '2026-06-30', '2026-06-01T08:00:00+07:00', '2026-06-30T23:59:00+07:00')
 *   // "01 Jun 2026, 08:00 — 30 Jun 2026, 23:59" (WIB user)
 *   // "01 Jun 2026, 09:00 — 01 Jul 2026, 00:59" (WITA user)
 */
export function formatPromoPeriod(
  startDate: string | null | undefined,
  endDate: string | null | undefined,
  startDatetime?: string | null,
  endDatetime?: string | null
): string {
  // If ISO datetime available, use it for timezone-aware formatting
  if (startDatetime && endDatetime) {
    const start = formatTimestamp(startDatetime, 'dd MMM yyyy, HH:mm');
    const end = formatTimestamp(endDatetime, 'dd MMM yyyy, HH:mm');
    return `${start} — ${end}`;
  }
  
  if (startDatetime) {
    const start = formatTimestamp(startDatetime, 'dd MMM yyyy, HH:mm');
    const end = formatDate(endDate);
    return `${start} — ${end}`;
  }
  
  if (endDatetime) {
    const start = formatDate(startDate);
    const end = formatTimestamp(endDatetime, 'dd MMM yyyy, HH:mm');
    return `${start} — ${end}`;
  }

  // Fallback: date only
  const start = formatDate(startDate);
  const end = formatDate(endDate);
  return `${start} — ${end}`;
}

/**
 * Format promotion end date with optional time (for short display, timezone-aware)
 * 
 * @example
 * formatPromoEnd('2026-06-30', '2026-06-30T23:59:00+07:00') // "30 Jun 2026, 23:59" (WIB)
 * formatPromoEnd('2026-06-30', null) // "30 Jun 2026"
 */
export function formatPromoEnd(
  endDate: string | null | undefined,
  endDatetime?: string | null
): string {
  if (endDatetime) {
    return formatTimestamp(endDatetime, 'dd MMM yyyy, HH:mm');
  }
  return formatDate(endDate);
}


/**
 * Smart format: shows relative time if recent, otherwise shows date
 * 
 * @example
 * formatSmart('2026-04-28T10:44:03.000Z') // "2 jam yang lalu" (if recent)
 * formatSmart('2026-01-01T10:44:03.000Z') // "01 Jan 2026" (if old)
 */
export function formatSmart(isoString: string | null | undefined): string {
  if (!isoString) return '-';
  
  try {
    const date = parseISO(isoString);
    const now = new Date();
    const diffInHours = (now.getTime() - date.getTime()) / (1000 * 60 * 60);
    
    // If less than 24 hours ago, show relative time
    if (diffInHours < 24 && diffInHours > 0) {
      return formatRelativeTime(isoString);
    }
    
    // Otherwise show date
    return formatTimestamp(isoString);
  } catch (error) {
    return formatTimestamp(isoString);
  }
}
