/**
 * Date utilities for US Floral Sistema
 * Handles Excel serial dates, date formatting (YYYY-MM-DD),
 * and ship date calculations per carrier rules (FedEx, UPS, etc.)
 */

export function parseExcelDate(val: any): Date {
  if (!val) return new Date();

  // Excel serial date number or numeric string (e.g. 46274 or "46274")
  if (typeof val === 'number' || (typeof val === 'string' && /^\d{4,6}$/.test(val.trim()))) {
    const num = Number(val);
    const utcMs = Math.round((num - 25569) * 86400 * 1000);
    const d = new Date(utcMs);
    return new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), 12, 0, 0));
  }

  if (typeof val === 'string') {
    const s = val.trim();
    // Check for YYYY-MM-DD or YYYY/MM/DD
    const mIso = s.match(/^(\d{4})[\/\-](\d{1,2})[\/\-](\d{1,2})/);
    if (mIso) {
      const year = parseInt(mIso[1], 10);
      const month = parseInt(mIso[2], 10);
      const day = parseInt(mIso[3], 10);
      return new Date(Date.UTC(year, month - 1, day, 12, 0, 0));
    }

    // Check for MM/DD/YYYY or MM-DD-YYYY
    const mUs = s.match(/^(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/);
    if (mUs) {
      const month = parseInt(mUs[1], 10);
      const day = parseInt(mUs[2], 10);
      const year = parseInt(mUs[3], 10);
      return new Date(Date.UTC(year, month - 1, day, 12, 0, 0));
    }

    const parsed = new Date(s);
    if (!isNaN(parsed.getTime())) {
      return new Date(Date.UTC(parsed.getUTCFullYear(), parsed.getUTCMonth(), parsed.getUTCDate(), 12, 0, 0));
    }
  }

  if (val instanceof Date && !isNaN(val.getTime())) {
    return new Date(Date.UTC(val.getUTCFullYear(), val.getUTCMonth(), val.getUTCDate(), 12, 0, 0));
  }

  return new Date();
}

/**
 * Returns a clean string in YYYY-MM-DD format from any date representation.
 */
export function formatDateToYYYYMMDD(val: any): string {
  if (!val && val !== 0) return '';
  if (typeof val === 'string') {
    const trimmed = val.trim();
    if (!trimmed) return '';
    if (/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) return trimmed;
  }

  try {
    const d = parseExcelDate(val);
    if (!d || isNaN(d.getTime())) return '';
    const y = d.getUTCFullYear();
    const m = String(d.getUTCMonth() + 1).padStart(2, '0');
    const day = String(d.getUTCDate()).padStart(2, '0');
    return `${y}-${m}-${day}`;
  } catch {
    return '';
  }
}

/**
 * Calculates ship date based on delivery date and carrier rules.
 * FEDEX:
 *   LUNES     -> JUEVES (-4 días)
 *   MARTES    -> VIERNES (-4 días)
 *   MIERCOLES -> SABADO (-4 días)
 *   JUEVES    -> LUNES (-3 días)
 *   VIERNES   -> MARTES (-3 días)
 *   SABADO    -> MIERCOLES (-3 días)
 *   DOMINGO   -> MIERCOLES (-4 días)
 *
 * UPS:
 *   LUNES     -> JUEVES (-4 días)
 *   MARTES    -> SABADO (-3 días)  <-- Diferencia con FedEx
 *   MIERCOLES -> SABADO (-4 días)
 *   JUEVES    -> LUNES (-3 días)
 *   VIERNES   -> MARTES (-3 días)
 *   SABADO    -> MIERCOLES (-3 días)
 *   DOMINGO   -> MIERCOLES (-4 días)
 */
export function calculateShipDate(deliveryDate: Date | string | number, agency?: string): string {
  if (!deliveryDate && deliveryDate !== 0) return '';
  const d = parseExcelDate(deliveryDate);
  if (!d || isNaN(d.getTime())) return '';

  const dayOfWeek = d.getUTCDay(); // 0 = Sun, 1 = Mon, 2 = Tue, 3 = Wed, 4 = Thu, 5 = Fri, 6 = Sat
  const isUps = (agency || '').toString().trim().toLowerCase().includes('ups');

  let daysToSubtract = 4;

  switch (dayOfWeek) {
    case 1: // LUNES -> JUEVES (-4 días)
      daysToSubtract = 4;
      break;
    case 2: // MARTES -> VIERNES (-4 días) (Regla corregida: siempre Viernes, nunca Sábado)
      daysToSubtract = 4;
      break;
    case 3: // MIERCOLES -> SABADO (-4 días)
      daysToSubtract = 4;
      break;
    case 4: // JUEVES -> LUNES (-3 días)
      daysToSubtract = 3;
      break;
    case 5: // VIERNES -> MARTES (-3 días)
      daysToSubtract = 3;
      break;
    case 6: // SABADO -> MIERCOLES (-3 días)
      daysToSubtract = 3;
      break;
    case 0: // DOMINGO -> MIERCOLES (-4 días)
      daysToSubtract = 4;
      break;
    default:
      daysToSubtract = 4;
  }

  const shipDate = new Date(d.getTime() - daysToSubtract * 86400000);
  const y = shipDate.getUTCFullYear();
  const m = String(shipDate.getUTCMonth() + 1).padStart(2, '0');
  const day = String(shipDate.getUTCDate()).padStart(2, '0');
  return `${y}-${m}-${day}`;
}

export type DateValidationWarning = {
  isWeekendDelivery: boolean;
  weekendDayName?: 'Sábado' | 'Domingo';
  isLeadTimeUrgent: boolean;   // <= 4 días
  isLeadTimeWarning: boolean;  // < 6 días
  leadTimeDays: number;
  hasWarning: boolean;
  warningMessages: string[];
};

/**
 * Validates order date against delivery date:
 * 1. Checks if delivery date falls on Saturday or Sunday (FedEx does not deliver on weekends).
 * 2. Checks if difference between order date and delivery date is <= 4 days (urgent) or < 6 days (lead time warning).
 */
export function validateOrderDates(orderDateVal: any, deliveryDateVal: any): DateValidationWarning {
  const warnings: string[] = [];
  let isWeekendDelivery = false;
  let weekendDayName: 'Sábado' | 'Domingo' | undefined = undefined;
  let isLeadTimeUrgent = false;
  let isLeadTimeWarning = false;
  let leadTimeDays = 999;

  if (deliveryDateVal) {
    const dDelivery = parseExcelDate(deliveryDateVal);
    const dayOfWeek = dDelivery.getUTCDay(); // 0 = Sun, 6 = Sat

    if (dayOfWeek === 6) {
      isWeekendDelivery = true;
      weekendDayName = 'Sábado';
      warnings.push('Entrega en Sábado: FedEx no tiene habilitadas entregas en fin de semana. Contactar al cliente para mover la fecha.');
    } else if (dayOfWeek === 0) {
      isWeekendDelivery = true;
      weekendDayName = 'Domingo';
      warnings.push('Entrega en Domingo: FedEx no tiene habilitadas entregas en fin de semana. Contactar al cliente para mover la fecha.');
    }

    if (orderDateVal) {
      const dOrder = parseExcelDate(orderDateVal);
      const diffMs = dDelivery.getTime() - dOrder.getTime();
      leadTimeDays = Math.round(diffMs / 86400000);

      if (leadTimeDays <= 4) {
        isLeadTimeUrgent = true;
        isLeadTimeWarning = true;
        if (leadTimeDays < 0) {
          warnings.push(`Fecha de entrega es anterior a la fecha de orden (${Math.abs(leadTimeDays)} días de diferencia). Mínimo requerido: 6 días.`);
        } else {
          warnings.push(`Anticipación crítica: solo ${leadTimeDays} día${leadTimeDays !== 1 ? 's' : ''} entre orden y entrega (mínimo requerido: 6 días, crítico <= 4 días).`);
        }
      } else if (leadTimeDays < 6) {
        isLeadTimeWarning = true;
        warnings.push(`Anticipación menor a 6 días: ${leadTimeDays} días entre orden y entrega.`);
      }
    }
  }

  return {
    isWeekendDelivery,
    weekendDayName,
    isLeadTimeUrgent,
    isLeadTimeWarning,
    leadTimeDays,
    hasWarning: isWeekendDelivery || isLeadTimeWarning,
    warningMessages: warnings
  };
}

