/**
 * Утилиты для работы с часовыми поясами.
 * 
 * Поддерживаемые форматы timezone:
 * - UTC+X, UTC-X (например, "UTC+8", "UTC-5")
 * - GMT+X, GMT-X
 * - IANA названия (например, "Europe/Moscow", "Asia/Irkutsk")
 */

/**
 * Парсить timezone и получить смещение в минутах.
 * 
 * Примеры:
 * - "UTC+8" -> 480 (8 * 60)
 * - "UTC-5" -> -300 (-5 * 60)
 * - "UTC+5:30" -> 330 (5 * 60 + 30)
 * 
 * @returns смещение в минутах или null если не удалось распарсить
 */
export function parseTimezoneOffset(timezone: string | undefined): number | null {
  if (!timezone) return null;
  
  const trimmed = timezone.trim();
  
  // Парсим формат UTC+X, UTC-X, GMT+X, GMT-X
  const match = trimmed.match(/^(?:UTC|GMT)([+-])(\d{1,2})(?::(\d{2}))?$/i);
  if (match) {
    const sign = match[1] === '+' ? 1 : -1;
    const hours = parseInt(match[2], 10);
    const minutes = match[3] ? parseInt(match[3], 10) : 0;
    return sign * (hours * 60 + minutes);
  }
  
  return null;
}

/**
 * Получить смещение часового пояса в минутах.
 * 
 * Поддерживает:
 * - UTC+X формат (парсит напрямую)
 * - IANA названия (использует Intl API)
 * 
 * @returns смещение в минутах (положительное = восток от UTC)
 */
export function getTimezoneOffsetMinutes(timezone: string | undefined): number {
  if (!timezone) {
    // Браузерный timezone
    return -new Date().getTimezoneOffset();
  }
  
  // Сначала пробуем распарсить UTC+X формат
  const parsedOffset = parseTimezoneOffset(timezone);
  if (parsedOffset !== null) {
    return parsedOffset;
  }
  
  // Для IANA названий используем Intl API
  try {
    const now = new Date();
    const utcDate = new Date(now.toLocaleString('en-US', { timeZone: 'UTC' }));
    const tzDate = new Date(now.toLocaleString('en-US', { timeZone: timezone }));
    return Math.round((tzDate.getTime() - utcDate.getTime()) / 60000);
  } catch {
    // Fallback на браузерный timezone
    return -new Date().getTimezoneOffset();
  }
}

/**
 * Создать ISO строку даты/времени с учетом часового пояса пользователя.
 * 
 * Пример: Если пользователь в Улан-Удэ (UTC+8) вводит 18:00,
 * то нужно отправить на сервер 10:00 UTC (18:00 - 8 часов).
 * 
 * @param dateStr - дата в формате 'YYYY-MM-DD'
 * @param timeStr - время в формате 'HH:mm'
 * @param userTimezone - часовой пояс пользователя (например, 'UTC+8', 'Europe/Moscow')
 * @returns ISO строка в UTC
 */
export function createDateTimeInUserTimezone(
  dateStr: string,
  timeStr: string,
  userTimezone: string | undefined
): string {
  // Парсим дату и время
  const [year, month, day] = dateStr.split('-').map(Number);
  const [hours, minutes] = timeStr.split(':').map(Number);
  
  // Создаем дату как будто она в UTC
  const utcDate = new Date(Date.UTC(year, month - 1, day, hours, minutes, 0, 0));
  
  // Получаем смещение timezone пользователя
  const offsetMinutes = getTimezoneOffsetMinutes(userTimezone);
  
  // Корректируем: вычитаем смещение, чтобы получить UTC
  // Например: 18:00 в UTC+8 = 10:00 UTC, значит вычитаем 8 часов (480 минут)
  utcDate.setMinutes(utcDate.getMinutes() - offsetMinutes);
  
  return utcDate.toISOString();
}

/**
 * Парсить ISO дату и получить локальную дату/время в часовом поясе пользователя.
 * 
 * Работает с любым форматом timezone:
 * - UTC+8: добавляет 8 часов к UTC
 * - Europe/Moscow: использует Intl API
 * 
 * @param isoString - ISO строка даты (например, '2026-02-21T10:00:00Z' для UTC)
 * @param userTimezone - часовой пояс пользователя (например, 'UTC+8')
 * @returns объект с date и time в часовом поясе пользователя
 */
export function parseISOToUserTimezone(
  isoString: string,
  userTimezone: string | undefined
): { date: string; time: string; dateObj: Date } {
  // Парсим ISO строку в UTC timestamp
  const utcDate = new Date(isoString);
  const utcMs = utcDate.getTime();
  
  // Получаем смещение timezone пользователя в минутах
  const offsetMinutes = getTimezoneOffsetMinutes(userTimezone);
  
  // Применяем смещение: UTC + offset = локальное время
  // Например: 10:00 UTC + 8 часов = 18:00 в UTC+8
  const localMs = utcMs + offsetMinutes * 60 * 1000;
  const localDate = new Date(localMs);
  
  // Извлекаем компоненты даты/времени в UTC (потому что мы уже добавили offset)
  const year = localDate.getUTCFullYear();
  const month = String(localDate.getUTCMonth() + 1).padStart(2, '0');
  const day = String(localDate.getUTCDate()).padStart(2, '0');
  const hours = String(localDate.getUTCHours()).padStart(2, '0');
  const minutes = String(localDate.getUTCMinutes()).padStart(2, '0');
  
  const dateStr = `${year}-${month}-${day}`;
  const timeStr = `${hours}:${minutes}`;
  
  // Создаем Date объект для использования в UI (в локальном времени браузера)
  const displayDate = new Date(`${dateStr}T${timeStr}`);
  
  return {
    date: dateStr,
    time: timeStr,
    dateObj: displayDate,
  };
}

/**
 * Форматировать дату для отображения в часовом поясе пользователя.
 * 
 * @param isoString - ISO строка даты
 * @param userTimezone - часовой пояс пользователя (например, 'UTC+8')
 * @param options - опции форматирования Intl.DateTimeFormat
 */
export function formatDateInUserTimezone(
  isoString: string,
  userTimezone: string | undefined,
  options: Intl.DateTimeFormatOptions = {}
): string {
  // Получаем локальное время в timezone пользователя
  const parsed = parseISOToUserTimezone(isoString, userTimezone);
  
  // Форматируем используя Intl (dateObj уже в правильном времени)
  return new Intl.DateTimeFormat('ru-RU', options).format(parsed.dateObj);
}

/**
 * Получить текущую дату/время в часовом поясе пользователя.
 */
export function getNowInUserTimezone(userTimezone: string | undefined): Date {
  const now = new Date();
  const parsed = parseISOToUserTimezone(now.toISOString(), userTimezone);
  return parsed.dateObj;
}

/**
 * Получить название часового пояса с offset.
 * Например: 'Europe/Moscow' -> 'Europe/Moscow (UTC+3)'
 * Для 'UTC+8' -> 'UTC+8'
 */
export function getTimezoneDisplayName(timezone: string): string {
  if (!timezone) return '';
  
  // Если уже в формате UTC+X, возвращаем как есть
  if (/^(?:UTC|GMT)[+-]\d/i.test(timezone)) {
    return timezone;
  }
  
  try {
    const offsetMinutes = getTimezoneOffsetMinutes(timezone);
    const hours = Math.floor(Math.abs(offsetMinutes) / 60);
    const mins = Math.abs(offsetMinutes) % 60;
    const sign = offsetMinutes >= 0 ? '+' : '-';
    const offsetStr = mins > 0 ? `${hours}:${mins.toString().padStart(2, '0')}` : `${hours}`;
    return `${timezone} (UTC${sign}${offsetStr})`;
  } catch {
    return timezone;
  }
}
