namespace Health.Application.Calendars;

public sealed class CalendarService(ICalendarRepository calendar) : ICalendarService
{
    private readonly ICalendarRepository _calendar = calendar;

    public async Task<IReadOnlyList<object>> GetMonthAsync(Guid userId, int year, int month, CancellationToken ct)
    {
        var start = new DateOnly(year, month, 1);
        var end = start.AddMonths(1);
        var snapshot = await _calendar.GetSnapshotAsync(userId, start, end, ct);
        var result = new List<object>();

        for (var date = start; date < end; date = date.AddDays(1))
        {
            var entries = BuildEntries(snapshot, date);
            if (entries.Count == 0) continue;

            result.Add(new
            {
                date = date.ToString("yyyy-MM-dd"),
                events = entries.Select(entry => entry.Type).Distinct().ToList(),
                details = entries.Select(entry => entry.Value).ToList()
            });
        }

        return result;
    }

    public async Task<object> GetDayAsync(Guid userId, DateOnly date, CancellationToken ct)
    {
        var snapshot = await _calendar.GetSnapshotAsync(userId, date, date.AddDays(1), ct);
        var medications = snapshot.Medications
            .Where(m => IsMedicationActiveOn(m, date))
            .Select(m => new { m.Name, m.Dosage, timeOfDay = m.TimeOfDay.Select(t => t.ToString(@"hh\:mm")).ToList() })
            .ToList();
        var exercises = snapshot.ExercisePlans
            .SelectMany(p => p.Items)
            .Where(i => i.ScheduledDate == date && !i.IsRestDay)
            .Select(i => new { type = i.ExerciseType, duration = i.DurationMinutes, isCompleted = i.IsCompleted, scheduledDate = i.ScheduledDate })
            .ToList();
        var followUps = snapshot.FollowUps
            .Where(f => DateOnly.FromDateTime(f.ScheduledAt) == date)
            .Select(f => new { f.Title, f.DoctorName, f.Department, status = f.Status.ToString() })
            .ToList();

        return new { medications, exercises, followUps };
    }

    private static List<CalendarEntry> BuildEntries(CalendarDataSnapshot snapshot, DateOnly date)
    {
        var entries = new List<CalendarEntry>();
        foreach (var medication in snapshot.Medications.Where(m => IsMedicationActiveOn(m, date)))
        {
            entries.Add(new CalendarEntry("medication", new
            {
                type = "medication",
                name = medication.Name,
                dosage = medication.Dosage,
                timeOfDay = medication.TimeOfDay.Select(t => t.ToString(@"hh\:mm")).ToList()
            }));
        }

        foreach (var plan in snapshot.ExercisePlans)
        {
            foreach (var item in plan.Items.Where(i => i.ScheduledDate == date && !i.IsRestDay))
                entries.Add(new CalendarEntry("exercise", new { type = "exercise", name = item.ExerciseType, duration = item.DurationMinutes, isCompleted = item.IsCompleted, scheduledDate = item.ScheduledDate }));
        }

        foreach (var followUp in snapshot.FollowUps.Where(f => DateOnly.FromDateTime(f.ScheduledAt) == date))
        {
            entries.Add(new CalendarEntry("followup", new
            {
                type = "followup",
                title = followUp.Title,
                doctorName = followUp.DoctorName,
                department = followUp.Department,
                status = followUp.Status.ToString()
            }));
        }

        return entries;
    }

    private static bool IsMedicationActiveOn(Health.Domain.Entities.Medication medication, DateOnly date) =>
        medication.IsActive
        && medication.TimeOfDay.Count > 0
        && (medication.StartDate == null || medication.StartDate <= date)
        && (medication.EndDate == null || medication.EndDate >= date);

    private sealed record CalendarEntry(string Type, object Value);
}
