/**
 * 📅 Utilities para manipulação de ranges de datas
 * 
 * Fornece funções prontas para gerar datas formatadas em ISO 8601
 * para uso em APIs e filtros de backend.
 */

export interface DateRange {
  start: string;
  end: string;
}

/**
 * 🎯 Classe utilitária para ranges de datas comuns
 */
export class DateRangeUtils {

  /**
   * Retorna o primeiro e último dia do mês atual em formato ISO 8601
   */
  static getCurrentMonthRange(): DateRange {
    const now = new Date();
    const year = now.getFullYear();
    const month = now.getMonth();

    // Primeiro dia do mês
    const firstDay = new Date(year, month, 1);
    
    // Último dia do mês (primeiro dia do próximo mês - 1 dia)
    const lastDay = new Date(year, month + 1, 0);

    return {
      start: this.formatToISO(firstDay),
      end: this.formatToISO(lastDay)
    };
  }

  /**
   * Retorna o primeiro e último dia do mês especificado em formato ISO 8601
   */
  static getMonthRange(year: number, month: number): DateRange {
    // Primeiro dia do mês (month é 0-based)
    const firstDay = new Date(year, month - 1, 1);
    
    // Último dia do mês
    const lastDay = new Date(year, month, 0);

    return {
      start: this.formatToISO(firstDay),
      end: this.formatToISO(lastDay)
    };
  }

  /**
   * Retorna o range dos últimos N dias em formato ISO 8601
   */
  static getLastNDaysRange(days: number): DateRange {
    const now = new Date();
    const startDate = new Date(now);
    startDate.setDate(now.getDate() - days);

    return {
      start: this.formatToISO(startDate),
      end: this.formatToISO(now)
    };
  }

  /**
   * Retorna o range do ano atual em formato ISO 8601
   */
  static getCurrentYearRange(): DateRange {
    const now = new Date();
    const year = now.getFullYear();

    return {
      start: `${year}-01-01`,
      end: `${year}-12-31`
    };
  }

  /**
   * Retorna o range personalizado em formato ISO 8601
   */
  static getCustomRange(startDate: Date, endDate: Date): DateRange {
    return {
      start: this.formatToISO(startDate),
      end: this.formatToISO(endDate)
    };
  }

  /**
   * Formata uma data para string ISO 8601 (YYYY-MM-DD)
   */
  static formatToISO(date: Date): string {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    
    return `${year}-${month}-${day}`;
  }

  /**
   * 🗓️ Formatar data para padrão ISO 8601 UTC (independente da região)
   * Versão robusta que lida com múltiplos formatos de entrada
   * 
   * @param date Data para formatar (string ou Date)
   * @param type 'start' = T00:00:00.000Z | 'end' = T23:59:59.000Z
   * @returns Formato: YYYY-MM-DDTHH:mm:ss.sssZ (sempre UTC)
   */
  static formatDateToISO(date?: string | Date, type: 'start' | 'end' = 'start'): string {
    if (!date) return '';
    
    // Se é um Date object, converter para string ISO primeiro
    if (date instanceof Date) {
      if (isNaN(date.getTime())) return '';
      date = date.toISOString().split('T')[0]; // YYYY-MM-DD
    }
    
    // Se já está no formato ISO 8601 completo com timezone
    if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(date)) {
      return date;
    }
    
    // Se está no formato de data simples (YYYY-MM-DD)
    if (/^\d{4}-\d{2}-\d{2}$/.test(date)) {
      // Criar data em UTC baseado no tipo
      if (type === 'end') {
        return date + 'T23:59:59-03:00'; // ✅ Final do dia em UTC
      } else {
        return date + 'T00:00:00-03:00'; // ✅ Início do dia em UTC
      }
    }
    
    // Converter outros formatos para ISO 8601 com timezone UTC
    const dateObj = new Date(date);
    if (isNaN(dateObj.getTime())) {
      return ''; // Retorna vazio se não conseguir converter
    }
    
    // Se é apenas uma data (sem horário), definir horário UTC baseado no tipo
    if (date.indexOf('T') === -1 && date.indexOf(' ') === -1) {
      if (type === 'end') {
        dateObj.setUTCHours(23, 59, 59, 0); // ✅ Final do dia UTC: 23:59:00.000Z
      } else {
        dateObj.setUTCHours(0, 0, 0, 0); // ✅ Início do dia UTC: 00:00:00.000Z
      }
    }
    
    return dateObj.toISOString(); // ✅ Formato completo em UTC: YYYY-MM-DDTHH:mm:ss.sssZ
  }

  /**
   * Formata uma data para string ISO 8601 completa com horário (YYYY-MM-DDTHH:mm:ss.sssZ)
   */
  static formatToISODateTime(date: Date): string {
    return date.toISOString();
  }

  /**
   * 🎯 HELPER: Retorna objeto pronto para query parameters de API
   * 
   * Exemplo de uso:
   * const filters = DateRangeUtils.getCurrentMonthAsApiParams();
   * // Resultado: { date_start: '2025-01-01', date_end: '2025-01-31' }
   */
  static getCurrentMonthAsApiParams(): { date_start: string; date_end: string } {
    const range = this.getCurrentMonthRange();
    return {
      date_start: range.start,
      date_end: range.end
    };
  }

  /**
   * 🎯 HELPER: Retorna objeto pronto para query parameters de API (range personalizado)
   */
  static getCustomRangeAsApiParams(startDate: Date, endDate: Date): { date_start: string; date_end: string } {
    const range = this.getCustomRange(startDate, endDate);
    return {
      date_start: range.start,
      date_end: range.end
    };
  }

  /**
   * 🎯 HELPER: Retorna objeto pronto para query parameters de API (últimos N dias)
   */
  static getLastNDaysAsApiParams(days: number): { date_start: string; date_end: string } {
    const range = this.getLastNDaysRange(days);
    return {
      date_start: range.start,
      date_end: range.end
    };
  }
}

/**
 * 🚀 SHORTCUTS para uso comum
 * 
 * Funções diretas para os casos mais frequentes
 */
export const DateRangeShortcuts = {
  /** Mês atual pronto para API com horários UTC precisos */
  currentMonth: () => {
    const range = DateRangeUtils.getCurrentMonthRange();
    return {
      date_start: DateRangeUtils.formatDateToISO(range.start, 'start'),
      date_end: DateRangeUtils.formatDateToISO(range.end, 'end')
    };
  },

  /** ✨ Mês anterior pronto para API com horários UTC precisos */
  previousMonth: () => {
    const now = new Date();
    const year = now.getFullYear();
    const month = now.getMonth();

    // Calcular mês anterior (lidar com janeiro -> dezembro do ano anterior)
    const previousYear = month === 0 ? year - 1 : year;
    const previousMonthIndex = month === 0 ? 11 : month - 1;

    // Primeiro dia do mês anterior
    const firstDay = new Date(previousYear, previousMonthIndex, 1);
    
    // Último dia do mês anterior
    const lastDay = new Date(previousYear, previousMonthIndex + 1, 0);

    const range = {
      start: DateRangeUtils.formatToISO(firstDay),
      end: DateRangeUtils.formatToISO(lastDay)
    };

    return {
      date_start: DateRangeUtils.formatDateToISO(range.start, 'start'),
      date_end: DateRangeUtils.formatDateToISO(range.end, 'end')
    };
  },
  
  /** Ano atual pronto para API com horários UTC precisos */
  currentYear: () => {
    const range = DateRangeUtils.getCurrentYearRange();
    return {
      date_start: DateRangeUtils.formatDateToISO(range.start, 'start'),
      date_end: DateRangeUtils.formatDateToISO(range.end, 'end')
    };
  },
  
  /** Últimos 30 dias pronto para API com horários UTC precisos */
  last30Days: () => {
    const range = DateRangeUtils.getLastNDaysRange(30);
    return {
      date_start: DateRangeUtils.formatDateToISO(range.start, 'start'),
      date_end: DateRangeUtils.formatDateToISO(range.end, 'end')
    };
  },
  
  /** Últimos 7 dias pronto para API com horários UTC precisos */
  last7Days: () => {
    const range = DateRangeUtils.getLastNDaysRange(7);
    return {
      date_start: DateRangeUtils.formatDateToISO(range.start, 'start'),
      date_end: DateRangeUtils.formatDateToISO(range.end, 'end')
    };
  },
  
  /** Ontem pronto para API com horários UTC precisos */
  yesterday: () => {
    const range = DateRangeUtils.getLastNDaysRange(1);
    return {
      date_start: DateRangeUtils.formatDateToISO(range.start, 'start'),
      date_end: DateRangeUtils.formatDateToISO(range.end, 'end')
    };
  },
  
  /** Hoje pronto para API com horários UTC precisos */
  today: () => {
    const today = DateRangeUtils.formatToISO(new Date());
    return {
      date_start: DateRangeUtils.formatDateToISO(today, 'start'),
      date_end: DateRangeUtils.formatDateToISO(today, 'end')
    };
  }
}; 