using System;
using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.ComponentModel;
using Itenso.TimePeriod;
using Wino.Core.Domain;
using Wino.Core.Domain.Entities.Calendar;
using Wino.Core.Domain.Extensions;
using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.Calendar;
namespace Wino.Calendar.ViewModels.Data;
public partial class CalendarItemViewModel : ObservableObject, ICalendarItem, ICalendarItemViewModel
{
public CalendarItem CalendarItem { get; }
public string Title => CalendarItem.Title;
public Guid Id => CalendarItem.Id;
public IAccountCalendar AssignedCalendar => CalendarItem.AssignedCalendar;
///
/// Gets or sets the start date converted to user's local timezone for display.
/// The underlying CalendarItem stores dates according to their timezone.
///
public DateTime StartDate
{
get
{
// Get start date in user's local timezone
return CalendarItem.LocalStartDate;
}
set
{
// When setting from UI (in local time), convert to event's timezone for storage.
CalendarItem.StartDate = value.ToTimeZoneFromLocal(CalendarItem.StartTimeZone);
}
}
///
/// Gets the end date converted to user's local timezone for display.
/// The underlying CalendarItem stores dates according to their timezone.
///
public DateTime EndDate
{
get
{
// Get end date in user's local timezone
return CalendarItem.LocalEndDate;
}
}
public double DurationInSeconds { get => CalendarItem.DurationInSeconds; set => CalendarItem.DurationInSeconds = value; }
///
/// Gets the time period in local time.
///
public ITimePeriod Period
{
get
{
// Return a period using local times for UI display
return new TimeRange(StartDate, EndDate);
}
}
public bool IsAllDayEvent => CalendarItem.IsAllDayEvent;
public bool IsMultiDayEvent => CalendarItem.IsMultiDayEvent;
public bool IsRecurringEvent => CalendarItem.IsRecurringEvent;
public bool IsRecurringChild => CalendarItem.IsRecurringChild;
public bool IsRecurringParent => CalendarItem.IsRecurringParent;
[ObservableProperty]
public partial bool IsSelected { get; set; }
[ObservableProperty]
public partial bool IsBusy { get; set; }
///
/// The period of the day where this item is currently being displayed.
/// Used for multi-day event title formatting.
///
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(DisplayTitle))]
public partial ITimePeriod DisplayingPeriod { get; set; }
///
/// Calendar settings for time formatting.
///
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(DisplayTitle))]
public partial CalendarSettings CalendarSettings { get; set; }
///
/// Gets the display title based on the current displaying period.
///
public string DisplayTitle
{
get
{
if (DisplayingPeriod == null || CalendarSettings == null)
return Title;
return GetDisplayTitle(DisplayingPeriod, CalendarSettings);
}
}
public ObservableCollection Attendees { get; } = new ObservableCollection();
public CalendarItemViewModel(CalendarItem calendarItem)
{
CalendarItem = calendarItem;
}
///
/// Updates the underlying CalendarItem with new data and raises property change notifications.
///
/// The updated calendar item data.
public void UpdateFrom(CalendarItem calendarItem)
{
if (calendarItem == null || calendarItem.Id != CalendarItem.Id)
return;
// Update all mutable properties
CalendarItem.Title = calendarItem.Title;
CalendarItem.Description = calendarItem.Description;
CalendarItem.Location = calendarItem.Location;
CalendarItem.StartDate = calendarItem.StartDate;
CalendarItem.StartTimeZone = calendarItem.StartTimeZone;
CalendarItem.EndTimeZone = calendarItem.EndTimeZone;
CalendarItem.DurationInSeconds = calendarItem.DurationInSeconds;
CalendarItem.Recurrence = calendarItem.Recurrence;
CalendarItem.RecurringCalendarItemId = calendarItem.RecurringCalendarItemId;
CalendarItem.OrganizerDisplayName = calendarItem.OrganizerDisplayName;
CalendarItem.OrganizerEmail = calendarItem.OrganizerEmail;
CalendarItem.IsLocked = calendarItem.IsLocked;
CalendarItem.IsHidden = calendarItem.IsHidden;
CalendarItem.CustomEventColorHex = calendarItem.CustomEventColorHex;
CalendarItem.HtmlLink = calendarItem.HtmlLink;
CalendarItem.Status = calendarItem.Status;
CalendarItem.Visibility = calendarItem.Visibility;
CalendarItem.ShowAs = calendarItem.ShowAs;
CalendarItem.UpdatedAt = calendarItem.UpdatedAt;
CalendarItem.AssignedCalendar = calendarItem.AssignedCalendar;
// Raise property changed for all bindable properties
OnPropertyChanged(nameof(Title));
OnPropertyChanged(nameof(StartDate));
OnPropertyChanged(nameof(EndDate));
OnPropertyChanged(nameof(DurationInSeconds));
OnPropertyChanged(nameof(Period));
OnPropertyChanged(nameof(IsAllDayEvent));
OnPropertyChanged(nameof(IsMultiDayEvent));
OnPropertyChanged(nameof(IsRecurringEvent));
OnPropertyChanged(nameof(IsRecurringChild));
OnPropertyChanged(nameof(IsRecurringParent));
OnPropertyChanged(nameof(AssignedCalendar));
OnPropertyChanged(nameof(DisplayTitle));
}
///
/// Gets the display title for this calendar item when rendered in a specific day.
///
public string GetDisplayTitle(ITimePeriod displayingPeriod, CalendarSettings calendarSettings)
{
if (!IsMultiDayEvent)
return Title;
var periodRelation = Period.GetRelation(displayingPeriod);
if (periodRelation == PeriodRelation.StartInside || periodRelation == PeriodRelation.EnclosingStartTouching)
{
// Event starts within this day: "HH:mm -> Title"
return $"{calendarSettings.GetTimeString(StartDate.TimeOfDay)} -> {Title}";
}
else if (periodRelation == PeriodRelation.EndInside || periodRelation == PeriodRelation.EnclosingEndTouching)
{
// Event ends within this day: "Title <- HH:mm"
return $"{Title} <- {calendarSettings.GetTimeString(EndDate.TimeOfDay)}";
}
else if (periodRelation == PeriodRelation.Enclosing)
{
// Event spans the entire day
return $"{Translator.CalendarItemAllDay} {Title}";
}
else
{
return Title;
}
}
public override string ToString() => CalendarItem.Title;
}