<script>
import { ref, computed, watch } from "vue";

/** Time & Date */
const week_opening_hours = ref({
  monday: { start: null, end: null },
  tuesday: { start: null, end: null },
  wednesday: { start: null, end: null },
  thursday: { start: null, end: null },
  friday: { start: null, end: null },
  saturday: { start: null, end: null }, // Saturday closed
  sunday: { start: null, end: null } // Sunday closed
});

const setWeekOpeningHours = (newHours) => {
  // Update the week opening hours with the new hours
  week_opening_hours.value = { ...week_opening_hours.value, ...newHours };
};

const getOpeningHours = (date) => {
  const dayOfWeek = date.getDay(); // 0 = Sunday, 1 = Monday, ..., 6 = Saturday
  const dayName = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'][dayOfWeek];
  console.log('getOpeningHours called for:', dayName, week_opening_hours.value[dayName]);

  return {
    start: {
      hour: week_opening_hours.value[dayName].start ? parseInt(week_opening_hours.value[dayName].start.split(':')[0]) : null,
      minute: week_opening_hours.value[dayName].start ? parseInt(week_opening_hours.value[dayName].start.split(':')[1]) : null
    },
    end: {
      hour: week_opening_hours.value[dayName].end ? parseInt(week_opening_hours.value[dayName].end.split(':')[0]) : null,
      minute: week_opening_hours.value[dayName].end ? parseInt(week_opening_hours.value[dayName].end.split(':')[1]) : null
    }
  }
};

const opening_hours = {
  week: week_opening_hours,
  set: setWeekOpeningHours,
  get: getOpeningHours
};

const date_selected = ref(new Date());
const date_selected_week_start = computed(() => {
  const date = new Date(date_selected.value);
  date.setDate(date.getDate() - date.getDay()); // Set to the start of the week (Sunday)
  return date;
});
const date_selected_week_end = computed(() => {
  const date = new Date(date_selected.value);
  date.setDate(date.getDate() + (6 - date.getDay())); // Set to the end of the week (Saturday)
  return date;
});
const date_week_previous = computed(() => {
  const date = new Date(date_selected.value);
  date.setDate(date.getDate() - 7); // Move to the previous week
  return date;
});
const date_week_next = computed(() => {
  const date = new Date(date_selected.value);
  date.setDate(date.getDate() + 7); // Move to the next week
  return date;
});
const date = {
  selected: date_selected,
  week: {
    start: date_selected_week_start,
    end: date_selected_week_end,
    next: () => {
      date_selected.value = date_week_next.value;
    },
    previous: () => {
      date_selected.value = date_week_previous.value;
    }
  },
  set: (newDate) => {
    date_selected.value = new Date(newDate);
  }
}

/** Time intervals */
const time_slot_duration = 30; // Duration of each time slot in minutes

const generateDefaultSlots = (day = null) => {
  const dateToUse = day ? new Date(day.date) : date_selected_week_start.value;
  // Start time for the debug slots (8 AM)
  const startTime = new Date(dateToUse);
  startTime.setHours(getOpeningHours(dateToUse).start.hour, getOpeningHours(dateToUse).start.minute, 0, 0); // Set to 8 AM
  // End time for the debug slots (6 PM)
  const endTime = new Date(dateToUse);
  endTime.setHours(getOpeningHours(dateToUse).end.hour, getOpeningHours(dateToUse).end.minute, 0, 0); // Set to 6 PM
  // Make sure there's actually time to book
  if (startTime >= endTime) {
    console.warn('No valid time slots available for the selected day:', dateToUse);
    return []; // No valid slots if start time is not before end time
  }
  // Generate time slots in the defined minute intervals
  const slots = [];
  for (let time = startTime; time <= endTime; time.setMinutes(time.getMinutes() + time_slot_duration)) {
    // Get the slots time after adding the duration
    let timeSlotEnd = new Date(time);
    timeSlotEnd.setMinutes(timeSlotEnd.getMinutes() + time_slot_duration);
    // Only add the slot if it is within the opening hours
    if (timeSlotEnd > endTime) {
      break; // Stop if the slot end time exceeds the end time
    }
    slots.push(new Date(time));
  }
  let result = [];
  // Assign the generated slots to debug_slots
  result = slots.map(slot => {
    return {
      date: slot,
      isAvailable: true, // At this stage, all slots are available, this is done to generate the grid
      layout: {
        classes: ['cell', 'has-radius-normal', 'has-background-success']
      }
    };
  });
  return result;
};
const reservation_slots = ref([]); // This will hold the booked slots
const addReservation = (slotDate, duration = time_slot_duration) => {
  // Add a reservation slot to the booked slots
  const endTime = new Date(slotDate);
  endTime.setMinutes(endTime.getMinutes() + duration);
  reservation_slots.value.push({
    date: slotDate, // Start time of the reservation
    endDate: endTime, // End time of the reservation
    duration: duration, // Duration in minutes
    isAvailable: false, // Mark as unavailable
    layout: cell_layout.unavailable
  });
};

const isTimeSlotAvailable = (slotDate) => {
  // Check if the slot is available based on the reservation slots
  for (const reservation of reservation_slots.value) {
    // Check if the slotDate falls within any of the reserved slots
    if (slotDate >= reservation.date && slotDate < reservation.endDate) {
      return false; // Slot is unavailable
    }
  }
  // If no reservations overlap, the slot is available
  return true;
};

const getDateSlots = (day) => {
  const result = generateDefaultSlots(day);
  return result.map(slot => {
    const slotDate = new Date(slot.date);
    const isAvailable = isTimeSlotAvailable(slotDate);
    return {
      ...slot,
      date: slotDate,
      isAvailable,
      layout: isAvailable
          ? isSlotSelected(slot)
            ? cell_layout.selected // If the slot is selected, use the selected layout
            : cell_layout.available // Otherwise, use the available layout
          : cell_layout.unavailable,
      isSelected: computed(() => isSlotSelected(slot)), // Computed property to check if the slot is selected
    };
  });
};

const slot_selected = ref(null); // This will hold the selected slot
const selectSlot = (slot) => {
  // Select a slot and update its layout
  if (slot_selected.value) {
    // Deselect the previously selected slot
    slot_selected.value.layout = cell_layout.available;
  }
  slot_selected.value = slot; // Set the new selected slot
  slot.layout = cell_layout.selected; // Update the layout of the selected slot
};
const isSlotSelected = (slot) => {
  // Check if the slot is currently selected
  return slot_selected.value && slot_selected.value.date.getTime() === slot.date.getTime();
};

const slots = {
  getDateSlots: getDateSlots,
  generateDefaultSlots: generateDefaultSlots,
  isTimeSlotAvailable: isTimeSlotAvailable,
  addReservation: addReservation,
  reservation_slots: reservation_slots,
  selected: slot_selected,
  select: selectSlot,
  isSelected: isSlotSelected
}


/** Time Bookings Process */

/** Layout */
const default_cell_layout = {
  classes: [
    'cell',
    'has-radius-normal',
  ]
};

const cell_layout = {
  available: {
    ... default_cell_layout,
    classes: [
      ...default_cell_layout.classes,
      'has-background-success-light',
      'is-clickable',
    ]
  },
  unavailable: {
    ... default_cell_layout,
    classes: [
      ...default_cell_layout.classes,
      'has-background-grey-lighter',
      'is-disabled',
    ]
  },
  selected: {
    ... default_cell_layout,
    classes: [
      ...default_cell_layout.classes,
      'has-background-success',
      'is-clickable',
    ]
  },
}

const grid_layout_default = {
  classes: [
    'fixed-grid',
  ]
};

const grid_layout_days = {
  ...grid_layout_default,
  classes: [
    ...grid_layout_default.classes,
  ],
  views: {
    work_week: {
      label: 'Work Week',
      classes: ['has-5-cols'],
      days: 5, // Monday to Friday
    },
    full_week: {
      label: 'Full Week',
      classes: ['has-7-cols'],
      days: 7, // Monday to Sunday
    }
  },
  view: 'work_week', // Default view
  week_start_day: 1, // Monday as the first day of the week
};

const layout = {
  cell: {
    ...cell_layout,
  },
  grid: {
    default: grid_layout_default,
    days: {
      ...grid_layout_days,
      classes: [
        ...grid_layout_default.classes,
        ...grid_layout_days.views[grid_layout_days.view].classes,
      ],
    },
  },
}

/** Days of the week */
const days_default = {
  label: 'Label',
  date: null
};

const sortDays = (days) => {
  return days.sort((a, b) => {
    const dayA = a.date.getDay();
    const dayB = b.date.getDay();
    // Adjust for the week start day
    return (dayA - grid_layout_days.week_start_day + 7) % 7 - (dayB - grid_layout_days.week_start_day + 7) % 7;
  });
};

const days = computed(() => {
  const weekStart = date_selected_week_start.value;
  const weekDays = [];
  for (let i = 0; i < 7; i++) {
    const day = new Date(weekStart);
    day.setDate(weekStart.getDate() + i);
    weekDays.push({
      ...days_default,
      label: day.toLocaleDateString('da-DK', { weekday: 'long' }),
      date: day,
      classes: ['day', 'has-text-centered']
    });
  }
  const sortedDays = sortDays(weekDays);
  // Apply the view configuration
  if (grid_layout_days.view === 'work_week') {
    // Filter to only include weekdays (Monday to Friday)
    return sortedDays.filter(day => {
      const dayIndex = (day.date.getDay() - grid_layout_days.week_start_day + 7) % 7; // Adjust for week start day
      return dayIndex < grid_layout_days.views.work_week.days; // Only include Monday to Friday
    });
  }
  // If full week view, return all days
  if (grid_layout_days.view === 'full_week') {
    return sortedDays;
  }
  // Fall back to default if no view is set
  console.warn('No valid view set for days, returning all days.', grid_layout_days.view, weekDays);
  // Sort the days to start from the configured week start day
  return sortedDays;
});

export const timeBookingsNewScheduler = {
  /** Date & Time */
  date: date,
  /** Time Slots */
  slots: slots,
  /** Layout */
  layout: layout,
  /** Days */
  days: days,
  /** Week Opening Hours */
  opening_hours: opening_hours,
}

</script>