import { WeekInfo, DayInfo } from '../types/shift';

/**
 * Get ISO week number (KW) for a given date
 * ISO 8601: Week starts on Monday, first week has Thursday of the year
 */
export const getISOWeek = (date: Date): number => {
  const d = new Date(date);
  d.setHours(0, 0, 0, 0);
  // Set to nearest Thursday: current date + 4 - current day number
  // Make Sunday's day number 7
  d.setDate(d.getDate() + 4 - (d.getDay() || 7));
  // Get first day of year
  const yearStart = new Date(d.getFullYear(), 0, 1);
  // Calculate full weeks to nearest Thursday
  const weekNo = Math.ceil((((d.getTime() - yearStart.getTime()) / 86400000) + 1) / 7);
  return weekNo;
};

/**
 * Get the year for ISO week
 * (December 29-31 might belong to next year's week 1)
 */
export const getISOWeekYear = (date: Date): number => {
  const d = new Date(date);
  d.setDate(d.getDate() + 4 - (d.getDay() || 7));
  return d.getFullYear();
};

/**
 * Get the first day (Monday) of a given ISO week
 */
export const getFirstDayOfISOWeek = (year: number, week: number): Date => {
  const simple = new Date(year, 0, 1 + (week - 1) * 7);
  const dow = simple.getDay();
  const ISOweekStart = simple;

  if (dow <= 4) {
    ISOweekStart.setDate(simple.getDate() - simple.getDay() + 1);
  } else {
    ISOweekStart.setDate(simple.getDate() + 8 - simple.getDay());
  }

  return ISOweekStart;
};

/**
 * Get complete week information including all 7 days
 */
export const getWeekInfo = (year: number, week: number): WeekInfo => {
  const startDate = getFirstDayOfISOWeek(year, week);
  const endDate = new Date(startDate);
  endDate.setDate(startDate.getDate() + 6);

  const days: DayInfo[] = [];
  const today = new Date();
  today.setHours(0, 0, 0, 0);

  const dayNames = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'];
  const monthNames = ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'];

  for (let i = 0; i < 7; i++) {
    const date = new Date(startDate);
    date.setDate(startDate.getDate() + i);

    days.push({
      date: date,
      dayName: dayNames[i],
      dayOfMonth: date.getDate(),
      month: monthNames[date.getMonth()],
      isToday: date.getTime() === today.getTime(),
      dateString: formatDateToISO(date),
    });
  }

  return {
    year,
    week,
    startDate,
    endDate,
    days,
  };
};

/**
 * Get current week info
 */
export const getCurrentWeekInfo = (): WeekInfo => {
  const today = new Date();
  const year = getISOWeekYear(today);
  const week = getISOWeek(today);
  return getWeekInfo(year, week);
};

/**
 * Navigate to previous week
 */
export const getPreviousWeek = (year: number, week: number): { year: number; week: number } => {
  if (week === 1) {
    // Go to last week of previous year
    const lastWeekOfPrevYear = getISOWeek(new Date(year - 1, 11, 28)); // Dec 28 is always in the last week
    return { year: year - 1, week: lastWeekOfPrevYear };
  }
  return { year, week: week - 1 };
};

/**
 * Navigate to next week
 */
export const getNextWeek = (year: number, week: number): { year: number; week: number } => {
  const lastWeekOfYear = getISOWeek(new Date(year, 11, 28)); // Dec 28 is always in the last week

  if (week === lastWeekOfYear) {
    // Go to first week of next year
    return { year: year + 1, week: 1 };
  }
  return { year, week: week + 1 };
};

/**
 * Format date to YYYY-MM-DD
 */
export const formatDateToISO = (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}`;
};

/**
 * Format time to HH:mm
 */
export const formatTime = (date: Date): string => {
  const hours = String(date.getHours()).padStart(2, '0');
  const minutes = String(date.getMinutes()).padStart(2, '0');
  return `${hours}:${minutes}`;
};

/**
 * Parse time string (HH:mm) to Date object (today's date with that time)
 */
export const parseTime = (timeString: string): Date => {
  const [hours, minutes] = timeString.split(':').map(Number);
  const date = new Date();
  date.setHours(hours, minutes, 0, 0);
  return date;
};

/**
 * Get day of week index (0 = Monday, 6 = Sunday) from Date
 */
export const getDayOfWeekIndex = (date: Date): number => {
  const day = date.getDay();
  return (day + 6) % 7; // Convert Sunday(0) to 6, Monday(1) to 0, etc.
};
