using Health.Domain.Entities;
using Health.Domain.Enums;

namespace Health.Application.Medications;

public sealed record MedicationUpsertRequest(
    string Name,
    string? Dosage,
    MedicationFrequency Frequency,
    IReadOnlyList<TimeOnly> TimeOfDay,
    DateOnly? StartDate,
    DateOnly? EndDate,
    MedicationSource Source,
    string? Notes);

public sealed record MedicationPatchRequest(
    string? Name,
    string? Dosage,
    MedicationFrequency? Frequency,
    IReadOnlyList<TimeOnly>? TimeOfDay,
    DateOnly? StartDate,
    DateOnly? EndDate,
    string? Notes);

public sealed record MedicationDto(
    Guid Id,
    string Name,
    string? Dosage,
    string Frequency,
    IReadOnlyList<TimeOnly> TimeOfDay,
    DateOnly? StartDate,
    DateOnly? EndDate,
    bool IsActive,
    string? Notes,
    string Source,
    DateTime CreatedAt,
    DateTime UpdatedAt,
    bool TodayTaken);

public sealed record MedicationReminderDto(
    Guid Id,
    string Name,
    string? Dosage,
    string ScheduledTime,
    string Status);

public sealed record MedicationReminderTask(
    Guid TaskId,
    Guid UserId,
    Guid MedicationId,
    string Name,
    string? Dosage,
    DateOnly ScheduledDate,
    TimeOnly ScheduledTime);

public interface IMedicationService
{
    Task<IReadOnlyList<MedicationDto>> ListAsync(Guid userId, string? filter, CancellationToken ct);
    Task<Guid> CreateAsync(Guid userId, MedicationUpsertRequest request, CancellationToken ct);
    Task<bool> UpdateAsync(Guid userId, Guid medicationId, MedicationPatchRequest request, CancellationToken ct);
    Task<bool> DeleteAsync(Guid userId, Guid medicationId, CancellationToken ct);
    Task<bool?> ToggleTodayTakenAsync(Guid userId, Guid medicationId, CancellationToken ct);
    Task<IReadOnlyList<MedicationReminderDto>> GetRemindersAsync(Guid userId, CancellationToken ct);
    Task<bool?> ConfirmDoseAsync(Guid userId, Guid medicationId, TimeOnly scheduledTime, MedicationLogStatus status, CancellationToken ct);
    Task<bool> CancelDoseAsync(Guid userId, Guid medicationId, TimeOnly scheduledTime, CancellationToken ct);
    Task<IReadOnlyList<MedicationDto>> ListActiveAsync(Guid userId, CancellationToken ct);
    Task<bool> ConfirmNowAsync(Guid userId, Guid medicationId, CancellationToken ct);
}

public interface IMedicationRepository
{
    Task<IReadOnlyList<Medication>> ListAsync(Guid userId, string? filter, CancellationToken ct);
    Task<IReadOnlyList<Medication>> ListActiveForRemindersAsync(Guid userId, DateOnly today, CancellationToken ct);
    Task<IReadOnlyList<MedicationLog>> ListLogsInWindowAsync(Guid userId, DateTime startUtc, DateTime endUtc, CancellationToken ct);
    Task<Medication?> GetOwnedAsync(Guid userId, Guid medicationId, CancellationToken ct);
    Task<bool> ExistsOwnedAsync(Guid userId, Guid medicationId, CancellationToken ct);
    Task<MedicationLog?> GetTodayTakenLogAsync(Guid userId, Guid medicationId, DateTime startUtc, DateTime endUtc, CancellationToken ct);
    Task<bool> DoseLogExistsAsync(Guid userId, Guid medicationId, TimeOnly scheduledTime, DateTime startUtc, DateTime endUtc, CancellationToken ct);
    Task<MedicationLog?> GetDoseLogAsync(Guid userId, Guid medicationId, TimeOnly scheduledTime, DateTime startUtc, DateTime endUtc, CancellationToken ct);
    Task<IReadOnlyList<Medication>> ListActiveForReminderScanAsync(CancellationToken ct);
    Task AddMedicationAsync(Medication medication, CancellationToken ct);
    Task AddLogAsync(MedicationLog log, CancellationToken ct);
    void DeleteMedication(Medication medication);
    void DeleteLog(MedicationLog log);
    Task SaveChangesAsync(CancellationToken ct);
}

public interface IMedicationReminderScanner
{
    Task<IReadOnlyList<MedicationReminderTask>> ScanAsync(DateTime utcNow, CancellationToken ct);
}

public interface IMedicationReminderQueue
{
    Task<bool> EnqueueAsync(MedicationReminderTask task, CancellationToken ct);
    Task RecoverStaleAsync(CancellationToken ct);
    Task<MedicationReminderTask?> TryTakeAsync(CancellationToken ct);
    Task CompleteAsync(Guid taskId, CancellationToken ct);
    Task RetryAsync(Guid taskId, string error, CancellationToken ct);
}

public interface IMedicationReminderDispatcher
{
    Task DispatchAsync(MedicationReminderTask task, CancellationToken ct);
}
