﻿namespace Aidlab
{
    public enum ActivityType : int
    {
        Unspecific = 0,
        Automotive = 1,
        Walking = 2,
        Running = 4,
        Cycling = 8,
        Still = 16,
    }

    public enum WearState : int
    {
        PlacedProperly = 0,
        PlacedUpsideDown = 1,
        Loose = 2,
        Detached = 3,
        Unknown = 4,
        Unsettled = 5,
    }

    public enum Exercise : int
    {
        None = -1,
        PushUp = 0,
        Jump = 1,
        SitUp = 2,
        Burpee = 3,
        PullUp = 4,
        Squat = 5,
        Plank = 6,
    }

    /// <summary>
    /// An event of the device at a moment or over a period. Its identity is its class, <see cref="Timestamp"/> and
    /// type-specific value, for example the anntyp and aux of an <see cref="EcgEvent"/>. A later event with the same
    /// identity updates the earlier one: the closing report of a period, with its end, replaces its open report, and a
    /// synchronized copy (<see cref="IsPast"/> true) replaces the live one. A period may stay open, for example after a
    /// power loss. Later versions may add event types, so handle unknown ones.
    /// </summary>
    public abstract class DeviceEvent
    {
        protected DeviceEvent(ulong timestamp, ulong? endTimestamp, float? confidence, bool isPast)
        {
            Timestamp = timestamp;
            EndTimestamp = endTimestamp;
            Confidence = confidence;
            IsPast = isPast;
        }

        /// <summary>Start, Unix time in milliseconds.</summary>
        public ulong Timestamp { get; }

        /// <summary>End, Unix time in milliseconds: <see cref="Timestamp"/> for a moment, null while the period lasts.</summary>
        public ulong? EndTimestamp { get; }

        /// <summary>From 0 to 1, or null when the detector reports none.</summary>
        public float? Confidence { get; }

        /// <summary>False for a live event, true for an event read from internal memory through synchronization.</summary>
        public bool IsPast { get; }
    }

    /// <summary>The wear state of the chest electrodes changed.</summary>
    public sealed class WearStateEvent : DeviceEvent
    {
        public WearStateEvent(ulong timestamp, ulong? endTimestamp, float? confidence, bool isPast, WearState wearState)
            : base(timestamp, endTimestamp, confidence, isPast)
        {
            WearState = wearState;
        }

        public WearState WearState { get; }
    }

    /// <summary>The wear state of the nasal cannula (Aidmed One) changed.</summary>
    public sealed class PressureWearStateEvent : DeviceEvent
    {
        public PressureWearStateEvent(ulong timestamp, ulong? endTimestamp, float? confidence, bool isPast, WearState wearState)
            : base(timestamp, endTimestamp, confidence, isPast)
        {
            WearState = wearState;
        }

        public WearState WearState { get; }
    }

    /// <summary>The wearer marked a moment, for example with the device button.</summary>
    public sealed class UserEvent : DeviceEvent
    {
        public UserEvent(ulong timestamp, ulong? endTimestamp, float? confidence, bool isPast)
            : base(timestamp, endTimestamp, confidence, isPast) { }
    }

    /// <summary>The SDK detected an exercise.</summary>
    public sealed class ExerciseEvent : DeviceEvent
    {
        public ExerciseEvent(ulong timestamp, ulong? endTimestamp, float? confidence, bool isPast, Exercise exercise)
            : base(timestamp, endTimestamp, confidence, isPast)
        {
            Exercise = exercise;
        }

        public Exercise Exercise { get; }
    }

    /// <summary>The wearer was doing an activity.</summary>
    public sealed class ActivityEvent : DeviceEvent
    {
        public ActivityEvent(ulong timestamp, ulong? endTimestamp, float? confidence, bool isPast, ActivityType activity)
            : base(timestamp, endTimestamp, confidence, isPast)
        {
            Activity = activity;
        }

        public ActivityType Activity { get; }
    }

    /// <summary>Events to report; list them in the events of collect.</summary>
    public enum DeviceEventType : int
    {
        /// <summary><see cref="WearStateEvent"/>s: the wear state of the chest electrodes.</summary>
        WearState = 0,
        /// <summary><see cref="PressureWearStateEvent"/>s: the wear state of the nasal cannula (Aidmed One).</summary>
        PressureWearState = 1,
        /// <summary><see cref="UserEvent"/>s: moments the wearer marked.</summary>
        User = 2,
        /// <summary><see cref="ExerciseEvent"/>s: exercises the SDK detected.</summary>
        Exercise = 3,
        /// <summary><see cref="ActivityEvent"/>s: activity periods.</summary>
        Activity = 4,
        Ecg = 5,
        Sleep = 6,
    }

    /// <summary>The rhythm or signal quality of an ECG rhythm or noise annotation.</summary>
    public enum EcgRhythm : int
    {
        AtrialFibrillation,
        SinusBradycardia,
        NormalSinus,
        /// <summary>Unreadable or noisy signal; see <see cref="EcgEvent.Subtyp"/>.</summary>
        Noise,
        Unknown,
    }

    /// <summary>
    /// A period of a night analyzed by the device; values are the stage codes the device reports.
    /// </summary>
    public enum SleepPeriod : int
    {
        Unknown = -1,
        /// <summary>Awake, including waking during the night.</summary>
        Wake = 2,
        Light = 3,
        Deep = 4,
        Rem = 5,
    }

    /// <summary>
    /// One WFDB annotation of the device's ECG analysis. A beat (anntyp 1, 5, 9 or 13) is a moment at its R peak with the
    /// probability of its class as <see cref="DeviceEvent.Confidence"/>. A rhythm (28) or noise (14) change is a period,
    /// reported once it ends.
    /// </summary>
    public sealed class EcgEvent : DeviceEvent
    {
        public EcgEvent(
            ulong timestamp, ulong? endTimestamp, float? confidence, bool isPast,
            int anntyp, int subtyp, string aux, EcgRhythm? rhythm, string modelVersion)
            : base(timestamp, endTimestamp, confidence, isPast)
        {
            Anntyp = anntyp;
            Subtyp = subtyp;
            Aux = aux;
            Rhythm = rhythm;
            ModelVersion = modelVersion;
        }

        /// <summary>
        /// WFDB anntyp: 1 normal (N), 5 premature ventricular contraction (V), 9 supraventricular premature beat (S),
        /// 13 unclassifiable (Q), 14 noise or 28 rhythm.
        /// </summary>
        public int Anntyp { get; }

        /// <summary>
        /// WFDB subtyp, 0 when the annotation has none. For noise, the high four bits mark unreadable signals and the
        /// low four noisy ones.
        /// </summary>
        public int Subtyp { get; }

        /// <summary>WFDB aux, for example "(AFIB", "(SBR" or "(N" of a rhythm, or null when the annotation has none.</summary>
        public string Aux { get; }

        /// <summary>The rhythm of a rhythm or noise annotation, null for other annotations.</summary>
        public EcgRhythm? Rhythm { get; }

        /// <summary>The analysis model as "major.minor.revision", or null when unknown.</summary>
        public string ModelVersion { get; }
    }

    /// <summary>
    /// A period of a night analyzed by the device, reported once the night closes. A night is its periods: sleep onset
    /// is the start of its first period and the final wake is the end of its last.
    /// </summary>
    public sealed class SleepEvent : DeviceEvent
    {
        public SleepEvent(
            ulong timestamp, ulong? endTimestamp, float? confidence, bool isPast, SleepPeriod period, string modelVersion)
            : base(timestamp, endTimestamp, confidence, isPast)
        {
            Period = period;
            ModelVersion = modelVersion;
        }

        public SleepPeriod Period { get; }

        /// <summary>The analysis model as "major.minor.revision", or null when unknown.</summary>
        public string ModelVersion { get; }
    }

    public enum SyncState : int
    {
        Start = 0,
        End = 1,
        Stop = 2,
        Empty = 3,
        Unavailable = 4,
    }

    public enum BodyPosition : int
    {
        Undefined = 0,
        Prone = 1,
        Supine = 2,
        LeftSide = 3,
        RightSide = 4,
    }

    /// <summary>
    /// Data types to collect. The values 4, 5, 9 and 13 are reserved; 5 is activity, which collect adds for
    /// <see cref="DeviceEventType.Activity"/>.
    /// </summary>
    public enum Signal : int
    {
        Ecg = 0,
        Respiration = 1,
        Temperature = 2,
        Motion = 3,
        Orientation = 6,
        Steps = 7,
        HeartRate = 8,
        SoundVolume = 10,
        Rr = 11,
        Pressure = 12,
        RespirationRate = 14,
        BodyPosition = 15,
        Eda = 16,
        Gps = 17,
    }
}
