#nullable enable
using Baya.Application.Models.Catalog;

namespace Baya.Application.Models.Booking;

/// <summary>
/// The role-agnostic booking detail projection. Carries both parties' ids so the query handler can authorize
/// the caller and decide address-snapshot visibility, plus the decrypted address snapshot (masked for the
/// nurse). Money is the raw IRR <c>long</c>; the mapper stringifies it for the wire.
/// </summary>
public record BookingDetailProjection(
    long Id,
    long BookingRequestId,
    string Status,
    long CustomerId,
    long NurseId,
    string NurseName,
    long PatientId,
    string PatientName,
    long VariantId,
    string VariantSnapshotJson,
    long CustomerAddressId,
    string AddressSnapshotJson,
    long GrossPriceIrr,
    long BalinyaarCommissionIrr,
    decimal PlatformFeeRate,
    long NursePayoutAmount,
    long? PspFeeAmount,
    short SessionCount,
    DateOnly ScheduledDate,
    TimeOnly ScheduledTimeStart,
    TimeOnly ScheduledTimeEnd,
    DateTime? ConfirmedAt,
    DateTime? CompletedAt,
    DateTime? CancelledAt,
    string? CancelledBy,
    string? CancellationReason,
    string? CancellationPolicyCode,
    decimal? CancellationRefundPercentage,
    long? RefundableAmountIrr,
    DateTime? DisputeWindowEndsAt,
    DateTimeOffset CreatedAt,
    IReadOnlyList<BookingSessionProjection> Sessions);

/// <summary>Per-visit projection embedded in <see cref="BookingDetailProjection"/>.</summary>
public record BookingSessionProjection(
    long Id,
    int SessionIndex,
    DateOnly ScheduledDate,
    TimeOnly ScheduledTimeStart,
    TimeOnly ScheduledTimeEnd,
    string Status,
    long VisitPayoutAmount,
    DateTime? PayoutEligibleAt,
    string? EvvStatus,
    DateTime? CheckInAt,
    DateTime? CheckOutAt,
    bool? CheckInAddressMatch);

/// <summary>
/// Everything <c>ConvertRequestToBookingCommand</c> needs to build a booking from an
/// <c>accepted_awaiting_payment</c> request in one read: the ids + participant user ids (for notifications),
/// the engagement schedule, and the source data for the two frozen snapshots.
/// </summary>
public record BookingConversionSource(
    long RequestId,
    string Status,
    long CustomerId,
    int CustomerUserId,
    long NurseId,
    int NurseUserId,
    long PatientId,
    string PatientName,
    long VariantId,
    long CustomerAddressId,
    DateOnly RequestedDate,
    TimeOnly RequestedTimeStart,
    TimeOnly RequestedTimeEnd,
    VariantSnapshot VariantSnapshot,
    AddressSnapshot AddressSnapshot);

/// <summary>The immutable address data frozen into <c>address_snapshot_json</c> at booking time — full,
/// decrypted, plus the geocoded coordinates the EVV distance check later reads (so EVV is independent of
/// later address edits).</summary>
public record AddressSnapshot(
    long AddressId,
    string Title,
    long CityId,
    string CityNameFa,
    string CityNameEn,
    long? DistrictId,
    string? DistrictNameFa,
    string? DistrictNameEn,
    string AddressLine,
    string PostalCode,
    string RecipientName,
    string RecipientPhone,
    decimal? Latitude,
    decimal? Longitude);

/// <summary>The two participant user ids for a booking — the recipients of booking notifications.</summary>
public record BookingParticipants(int CustomerUserId, int NurseUserId);

/// <summary>The authorization envelope for the gated care-instructions read: the booking's status + both
/// party ids, plus the decrypted instructions (null when none written yet). The handler enforces the
/// two-stage disclosure boundary from these facts before ever surfacing <see cref="Instructions"/>.</summary>
public record CareInstructionsGate(string BookingStatus, long NurseId, long CustomerId, CareInstructionsDto? Instructions);

/// <summary>The authorization envelope for the per-session EVV read: both party ids + the EVV detail (null
/// when no verification exists yet). Raw GPS is surfaced only to the owning nurse + admin.</summary>
public record EvvGate(long NurseId, long CustomerId, VisitVerificationDto? Evv);
