/**
 * Date Formatting Utilities
 *
 * Provides utilities for formatting dates in German locale and converting
 * between different date formats for display and database storage.
 */

/**
 * Format a date to German format (DD.MM.YYYY)
 *
 * @param date - Date to format (Date object, ISO string, or timestamp)
 * @returns Formatted date string (e.g., "24.12.2024")
 *
 * @example
 * formatDateGerman(new Date('2024-12-24'))
 * // => "24.12.2024"
 *
 * formatDateGerman('2024-12-24T10:30:00Z')
 * // => "24.12.2024"
 */
export function formatDateGerman(date: Date | string | number): string {
  const dateObj = typeof date === 'string' || typeof date === 'number' ? new Date(date) : date

  if (isNaN(dateObj.getTime())) {
    return ''
  }

  return dateObj.toLocaleDateString('de-DE', {
    day: '2-digit',
    month: '2-digit',
    year: 'numeric',
  })
}

/**
 * Format a date to German long format (e.g., "24. Dezember 2024")
 *
 * @param date - Date to format
 * @returns Formatted date string with month name
 *
 * @example
 * formatDateGermanLong(new Date('2024-12-24'))
 * // => "24. Dezember 2024"
 */
export function formatDateGermanLong(date: Date | string | number): string {
  const dateObj = typeof date === 'string' || typeof date === 'number' ? new Date(date) : date

  if (isNaN(dateObj.getTime())) {
    return ''
  }

  return dateObj.toLocaleDateString('de-DE', {
    day: 'numeric',
    month: 'long',
    year: 'numeric',
  })
}

/**
 * Format a date with time to German format (DD.MM.YYYY HH:MM)
 *
 * @param date - Date to format
 * @returns Formatted datetime string
 *
 * @example
 * formatDateTimeGerman(new Date('2024-12-24T15:30:00Z'))
 * // => "24.12.2024 15:30"
 */
export function formatDateTimeGerman(date: Date | string | number): string {
  const dateObj = typeof date === 'string' || typeof date === 'number' ? new Date(date) : date

  if (isNaN(dateObj.getTime())) {
    return ''
  }

  return dateObj.toLocaleString('de-DE', {
    day: '2-digit',
    month: '2-digit',
    year: 'numeric',
    hour: '2-digit',
    minute: '2-digit',
  })
}

/**
 * Parse a date input string (DD.MM.YYYY or YYYY-MM-DD) to ISO format (YYYY-MM-DD)
 * Suitable for database storage and HTML date inputs
 *
 * @param dateString - Date string in DD.MM.YYYY or YYYY-MM-DD format
 * @returns ISO date string (YYYY-MM-DD) or null if invalid
 *
 * @example
 * parseDateToISO('24.12.2024')
 * // => "2024-12-24"
 *
 * parseDateToISO('2024-12-24')
 * // => "2024-12-24"
 *
 * parseDateToISO('invalid')
 * // => null
 */
export function parseDateToISO(dateString: string): string | null {
  if (!dateString || dateString.trim() === '') {
    return null
  }

  // Check if already in ISO format (YYYY-MM-DD)
  if (/^\d{4}-\d{2}-\d{2}$/.test(dateString)) {
    const date = new Date(dateString)
    return isNaN(date.getTime()) ? null : dateString
  }

  // Parse German format (DD.MM.YYYY)
  const germanMatch = dateString.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})$/)
  if (germanMatch) {
    const [, day, month, year] = germanMatch
    const paddedDay = day.padStart(2, '0')
    const paddedMonth = month.padStart(2, '0')
    const isoDate = `${year}-${paddedMonth}-${paddedDay}`

    // Validate the date
    const date = new Date(isoDate)
    if (isNaN(date.getTime())) {
      return null
    }

    return isoDate
  }

  return null
}

/**
 * Convert ISO date string (YYYY-MM-DD) to German format (DD.MM.YYYY)
 *
 * @param isoDate - ISO date string (YYYY-MM-DD)
 * @returns German date string (DD.MM.YYYY) or empty string if invalid
 *
 * @example
 * isoToGermanDate('2024-12-24')
 * // => "24.12.2024"
 */
export function isoToGermanDate(isoDate: string): string {
  if (!isoDate || !/^\d{4}-\d{2}-\d{2}$/.test(isoDate)) {
    return ''
  }

  const [year, month, day] = isoDate.split('-')
  return `${day}.${month}.${year}`
}

/**
 * Validate if a date of birth indicates a person is at least 18 years old
 *
 * @param dateOfBirth - Date of birth (Date object, ISO string, or German format)
 * @returns true if person is 18 or older
 *
 * @example
 * isAgeAtLeast18(new Date('2000-01-01'))
 * // => true (as of 2024)
 *
 * isAgeAtLeast18('01.01.2010')
 * // => false (as of 2024)
 */
export function isAgeAtLeast18(dateOfBirth: Date | string): boolean {
  let dateObj: Date

  if (typeof dateOfBirth === 'string') {
    // Try parsing German format first
    const isoDate = parseDateToISO(dateOfBirth)
    if (isoDate) {
      dateObj = new Date(isoDate)
    } else {
      dateObj = new Date(dateOfBirth)
    }
  } else {
    dateObj = dateOfBirth
  }

  if (isNaN(dateObj.getTime())) {
    return false
  }

  const today = new Date()
  const age = today.getFullYear() - dateObj.getFullYear()
  const monthDiff = today.getMonth() - dateObj.getMonth()
  const dayDiff = today.getDate() - dateObj.getDate()

  // Check if birthday has occurred this year
  if (monthDiff < 0 || (monthDiff === 0 && dayDiff < 0)) {
    return age - 1 >= 18
  }

  return age >= 18
}

/**
 * Format a relative date (e.g., "vor 2 Tagen", "gerade eben")
 *
 * @param date - Date to format
 * @returns Relative time string in German
 *
 * @example
 * formatRelativeDate(new Date(Date.now() - 1000 * 60 * 5))
 * // => "vor 5 Minuten"
 */
export function formatRelativeDate(date: Date | string | number): string {
  const dateObj = typeof date === 'string' || typeof date === 'number' ? new Date(date) : date

  if (isNaN(dateObj.getTime())) {
    return ''
  }

  const now = new Date()
  const diffMs = now.getTime() - dateObj.getTime()
  const diffSecs = Math.floor(diffMs / 1000)
  const diffMins = Math.floor(diffSecs / 60)
  const diffHours = Math.floor(diffMins / 60)
  const diffDays = Math.floor(diffHours / 24)

  if (diffSecs < 60) {
    return 'gerade eben'
  }

  if (diffMins < 60) {
    return `vor ${diffMins} ${diffMins === 1 ? 'Minute' : 'Minuten'}`
  }

  if (diffHours < 24) {
    return `vor ${diffHours} ${diffHours === 1 ? 'Stunde' : 'Stunden'}`
  }

  if (diffDays < 7) {
    return `vor ${diffDays} ${diffDays === 1 ? 'Tag' : 'Tagen'}`
  }

  if (diffDays < 30) {
    const weeks = Math.floor(diffDays / 7)
    return `vor ${weeks} ${weeks === 1 ? 'Woche' : 'Wochen'}`
  }

  if (diffDays < 365) {
    const months = Math.floor(diffDays / 30)
    return `vor ${months} ${months === 1 ? 'Monat' : 'Monaten'}`
  }

  const years = Math.floor(diffDays / 365)
  return `vor ${years} ${years === 1 ? 'Jahr' : 'Jahren'}`
}

/**
 * Get today's date in ISO format (YYYY-MM-DD)
 *
 * @returns Today's date in ISO format
 *
 * @example
 * getTodayISO()
 * // => "2024-12-24"
 */
export function getTodayISO(): string {
  const today = new Date()
  return today.toISOString().split('T')[0]
}

/**
 * Validate if a date is in the future
 *
 * @param date - Date to validate
 * @returns true if date is in the future
 */
export function isDateInFuture(date: Date | string): boolean {
  const dateObj = typeof date === 'string' ? new Date(date) : date

  if (isNaN(dateObj.getTime())) {
    return false
  }

  return dateObj.getTime() > Date.now()
}

/**
 * Validate if a date is in the past
 *
 * @param date - Date to validate
 * @returns true if date is in the past
 */
export function isDateInPast(date: Date | string): boolean {
  const dateObj = typeof date === 'string' ? new Date(date) : date

  if (isNaN(dateObj.getTime())) {
    return false
  }

  return dateObj.getTime() < Date.now()
}
