using System;
using System.Diagnostics;

namespace AsbCloudApp.Data
{
    /// <summary>
    /// Информация о фоновой работе
    /// </summary>
    public class BackgroundWorkDto
    {
        /// <summary>
        /// Идентификатор работы. Должен быть уникальным. Используется в логах и передается в колбэки.
        /// </summary>
        public string Id { get; init; } = null!;

        /// <summary>
        /// Класс описания состояния
        /// </summary>
        public class CurrentStateInfo
        {
            private string state = "start";

            /// <summary>
            /// Время последнего запуска
            /// </summary>
            public DateTime Start { get; } = DateTime.Now;

            /// <summary>
            /// Текущее время выполнения
            /// </summary>
            public TimeSpan ExecutionTime => DateTime.Now - Start;

            /// <summary>
            /// Текстовое описание того, что происходит в задаче.
            /// </summary>
            public string State
            {
                get => state;
                internal set
                {
                    state = value;
                    StateUpdate = DateTime.Now;
                }
            }

            /// <summary>
            /// Прогресс
            /// </summary>
            public double Progress { get; internal set; } = 0;

            /// <summary>
            /// Время последнего запуска
            /// </summary>
            public DateTime StateUpdate { get; private set; } = DateTime.Now;
        }

        /// <summary>
        /// Инфо о последней ошибке
        /// </summary>
        public class LastErrorInfo : LastCompleteInfo
        {
            /// <summary>
            /// 
            /// </summary>
            /// <param name="state"></param>
            /// <param name="errorText"></param>
            public LastErrorInfo(CurrentStateInfo state, string errorText)
                : base(state)
            {
                ErrorText = errorText;
            }

            /// <summary>
            /// Последняя ошибка
            /// </summary>
            public string ErrorText { get; init; } = null!;
        }

        /// <summary>
        /// Инфо о последнем завершении
        /// </summary>
        public class LastCompleteInfo
        {
            /// <summary>
            /// Дата запуска
            /// </summary>
            public DateTime Start { get; init; }

            /// <summary>
            /// Дата завершения
            /// </summary>
            public DateTime End { get; init; }

            /// <summary>
            /// Продолжительность последнего выполнения
            /// </summary>
            public TimeSpan ExecutionTime => End - Start;

            /// <summary>
            /// Состояние на момент завершения
            /// </summary>
            public string State { get; init; }

            /// <summary>
            /// ctor
            /// </summary>
            /// <param name="state"></param>
            public LastCompleteInfo(CurrentStateInfo state)
            {
                Start = state.Start;
                End = DateTime.Now;
                State = state.State;
            }
        }

        /// <summary>
        /// Текущее состояние
        /// </summary>
        public CurrentStateInfo? CurrentState { get; private set; }

        /// <summary>
        /// Последняя ошибка
        /// </summary>
        public LastErrorInfo? LastError { get; private set; }

        /// <summary>
        /// Последняя завершенная
        /// </summary>
        public LastCompleteInfo? LastComplete { get; private set; }

        /// <summary>
        /// Кол-во запусков
        /// </summary>
        public int CountStart { get; private set; }

        /// <summary>
        /// Кол-во завершений
        /// </summary>
        public int CountComplete { get; private set; }

        /// <summary>
        /// Кол-во ошибок
        /// </summary>
        public int CountErrors { get; private set; }

        /// <summary>
        /// Максимально допустимое время выполнения работы
        /// </summary>
        public TimeSpan Timeout { get; set; } = TimeSpan.FromMinutes(1);

        private string WorkNameForTrace => $"Backgroud work:\"{Id}\"";

        /// <summary>
        /// Обновления состояния при запуске работы
        /// </summary>
        protected void SetStatusStart()
        {
            CurrentState = new();
            CountStart++;
            Trace.TraceInformation($"{WorkNameForTrace} state: starting");
        }

        /// <summary>
        /// Обновления состояния в процессе работы
        /// </summary>
        protected void UpdateStatus(string newState, double? progress)
        {
            if (CurrentState is null)
                return;

            CurrentState.State = newState;
            if (progress.HasValue)
                CurrentState.Progress = progress.Value;

            Trace.TraceInformation($"{WorkNameForTrace} state[{100*progress:#}%]: {newState}");
        }

        /// <summary>
        /// Обновления состояния при успешном завершении работы
        /// </summary>
        protected void SetStatusComplete()
        {
            CountComplete++;
            if (CurrentState is null)
                return;

            LastComplete = new(CurrentState);
            CurrentState = null;
            Trace.TraceInformation($"{WorkNameForTrace} state: completed");
        }

        /// <summary>
        /// Обновления состояния при ошибке в работе
        /// </summary>
        protected void SetLastError(string errorMessage)
        {
            CountErrors++;
            if (CurrentState is null)
                return;

            LastError = new LastErrorInfo(CurrentState, errorMessage);
            CurrentState = null;
            Trace.TraceError($"{WorkNameForTrace} throw exception[{CountErrors}]: {errorMessage}");
        }
    }
}