import { clsx, type ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'
import { FixedDebt, VariableDebt, CardPayment } from './types'

/**
 * Combina clases de Tailwind CSS usando clsx y tailwind-merge
 * Permite combinar múltiples clases condicionalmente
 */
export function cn(...inputs: ClassValue[]): string {
  return twMerge(clsx(inputs))
}

/**
 * Formatea un número como moneda (pesos argentinos/USD)
 * Ejemplo: 1500.50 -> "$ 1.500,50"
 */
export function formatCurrency(amount: number): string {
  const formatter = new Intl.NumberFormat('es-AR', {
    style: 'currency',
    currency: 'ARS',
    minimumFractionDigits: 2,
    maximumFractionDigits: 2,
  })
  return formatter.format(amount)
}

/**
 * Formatea una fecha en formato legible en español
 * Ejemplo: "28 de enero de 2026"
 */
export function formatDate(date: string | Date): string {
  const d = typeof date === 'string' ? new Date(date) : date
  const formatter = new Intl.DateTimeFormat('es-AR', {
    day: 'numeric',
    month: 'long',
    year: 'numeric',
  })
  return formatter.format(d)
}

/**
 * Formatea una fecha en formato corto
 * Ejemplo: "28/01/2026"
 */
export function formatShortDate(date: string | Date): string {
  const d = typeof date === 'string' ? new Date(date) : date
  const formatter = new Intl.DateTimeFormat('es-AR', {
    day: '2-digit',
    month: '2-digit',
    year: 'numeric',
  })
  return formatter.format(d)
}

/**
 * Calcula los días hasta una fecha específica
 * Retorna un número negativo si la fecha ya pasó
 */
export function getDaysUntil(date: string | Date): number {
  const targetDate = typeof date === 'string' ? new Date(date) : date
  const today = new Date()

  // Reset hours to compare only dates
  const target = new Date(targetDate.getFullYear(), targetDate.getMonth(), targetDate.getDate())
  const current = new Date(today.getFullYear(), today.getMonth(), today.getDate())

  const diffTime = target.getTime() - current.getTime()
  const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))

  return diffDays
}

/**
 * Obtiene la próxima fecha para un día específico del mes
 * Si el día ya pasó este mes, devuelve el del mes siguiente
 */
export function getNextDateByDay(dayOfMonth: number): Date {
  const today = new Date()
  const currentYear = today.getFullYear()
  const currentMonth = today.getMonth()
  const currentDay = today.getDate()

  let targetYear = currentYear
  let targetMonth = currentMonth

  // Si el día ya pasó este mes, ir al siguiente mes
  if (currentDay > dayOfMonth) {
    targetMonth += 1
    if (targetMonth > 11) {
      targetMonth = 0
      targetYear += 1
    }
  }

  // Ajustar si el día no existe en el mes objetivo (ej: 31 de febrero)
  const lastDayOfMonth = new Date(targetYear, targetMonth + 1, 0).getDate()
  const targetDay = Math.min(dayOfMonth, lastDayOfMonth)

  return new Date(targetYear, targetMonth, targetDay)
}

/**
 * Obtiene el nombre del mes en español
 * El mes debe ser 1-12 (enero = 1)
 */
export function getMonthName(month: number): string {
  const monthNames = [
    'enero',
    'febrero',
    'marzo',
    'abril',
    'mayo',
    'junio',
    'julio',
    'agosto',
    'septiembre',
    'octubre',
    'noviembre',
    'diciembre',
  ]

  if (month < 1 || month > 12) {
    throw new Error('El mes debe estar entre 1 y 12')
  }

  return monthNames[month - 1]
}

/**
 * Calcula el total de deudas fijas no pagadas
 */
export function calculateTotalFixedDebts(debts: FixedDebt[]): number {
  return debts
    .filter((debt) => !debt.isPaid)
    .reduce((total, debt) => total + debt.amount, 0)
}

/**
 * Calcula el total de deudas variables no pagadas
 */
export function calculateTotalVariableDebts(debts: VariableDebt[]): number {
  return debts
    .filter((debt) => !debt.isPaid)
    .reduce((total, debt) => total + debt.amount, 0)
}

/**
 * Calcula el total de pagos de tarjeta
 * Opcionalmente filtrados por cardId
 */
export function calculateCardPayments(
  payments: CardPayment[],
  cardId?: string
): number {
  const filteredPayments = cardId
    ? payments.filter((payment) => payment.cardId === cardId)
    : payments

  return filteredPayments.reduce((total, payment) => total + payment.amount, 0)
}

/**
 * Calcula la próxima fecha de cierre de tarjeta
 * Si el día de cierre ya pasó este mes, devuelve el del mes siguiente
 */
export function calculateNextClosingDate(closingDay: number): Date {
  return getNextDateByDay(closingDay)
}

/**
 * Calcula la próxima fecha de vencimiento de tarjeta
 * Si el día de vencimiento ya pasó este mes, devuelve el del mes siguiente
 */
export function calculateNextDueDate(dueDay: number): Date {
  return getNextDateByDay(dueDay)
}

/**
 * Calcula el porcentaje de utilización de una tarjeta de crédito
 * Retorna un valor entre 0 y 100
 */
export function getCardUtilization(balance: number, limit: number): number {
  if (limit <= 0) {
    return 0
  }

  const utilization = (balance / limit) * 100
  return Math.min(Math.max(utilization, 0), 100)
}
